pytest -> 如何在 class 下的测试方法中使用 fixture return 值
pytest -> How to use fixture return value in test method under a class
我有一个夹具 returns 值如下:
import pytest
@pytest.yield_fixture(scope="module")
def oneTimeSetUp(browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
yield driver
print("Running one time tearDown")
这个装置从另一个正在读取命令行选项的装置获取浏览器值。
然后我有一个测试class,其中我有多个测试方法,它们都希望使用相同的返回值驱动程序来继续测试。
import pytest
@pytest.mark.usefixtures("oneTimeSetUp")
class TestClassDemo():
def test_methodA(self):
# I would like to use the driver value here
# How could I do this?
# Something like this
self.driver.get("https://www.google.com")
self.driver.find_element(By.ID, "some id")
print("Running method A")
def test_methodB(self):
print("Running method B")
使用 self.driver 失败并显示错误消息
self = <test_class_demo.TestClassDemo object at 0x102fb6c18>
def test_methodA(self):
> self.driver.get("https://www.google.com")
E AttributeError: 'TestClassDemo' object has no attribute 'driver'
我知道我可以将夹具作为参数传递给每个我想使用它的方法,但这不是最好的方法,因为我在每个方法中都需要它并且应该可以将它传递给class 然后在所有测试方法中使用它。
使驱动程序对象可用于方法的最佳方法是什么?
编辑 1:
按照建议在 conftest.py 中创建夹具
@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
## add `driver` attribute to the class under test -->
if request.cls is not None:
request.cls.driver = driver
## <--
yield driver
print("Running one time tearDown")
我还有一个 class,TestClassDemo 中需要哪个对象,我需要将相同的驱动程序实例传递给 class。将其视为 class ABC
class ABC():
def __init(self, driver):
self.driver = driver
def enterName(self):
# Do something with driver instance
然后在TestClassDemo
@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class TestClassDemo(unittest.TestCase):
# I need to create an object of class ABC, so that I can use it here
# abc = ABC(self.driver)
@pytest.fixture(scope="class", autouse=True)
def setup(self):
self.abc = ABC(self.driver)
# I tried this, but it's not working
# This error message shows up
# AttributeError: 'TestClassDemo' object has no attribute 'driver'
def setup_module(self):
self.abc = ABC(self.driver)
# This also does not work
# Error message -> AttributeError: 'TestClassDemo' object has no attribute 'abc'
def test_methodA(self):
self.driver.get("https://google.com")
self.abc.enterName("test")
print("Running method A")
def test_methodB(self):
self.abc.enterName("test")
print("Running method B")
这个 abc 对象应该也可以在其他测试方法中使用。
所有这些 class 都在单独的模块中,我的意思是说在单独的 .py 文件中。
另外请在回答中说明什么是替代 yield 驱动程序实例的最佳使用方法。
编辑 2:
对于这个没有 yield 的例子,运行 oneTimeTearDown 的最佳方法是什么?在 yield
之后,我正在 运行 执行拆解步骤
@pytest.fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
我也尝试使用 UnitTest class,但是当我使用 def setUpClass(cls) 时,我无法使用在 test_ 方法中实例化的对象。所以我无法弄清楚如何实现这一目标。
我还想从命令行提供命令行参数,例如浏览器,当我尝试 unittest 时,我不得不在每个 class 中编写命令行参数。我只想在一个地方提供它们,比如测试套件。所以 conftest 在这里帮助了我。
我有一个关于 Whosebug 的问题,但没有得到回复。你能看看那个吗?
Python unittest passing arguments to parent test class
谢谢
谢谢
py.text unittest integration documentation 中概述了一项可能对您有所帮助的技术...使用内置的 request
夹具。否则,我不知道在不提供命名夹具作为方法参数的情况下访问夹具的 return 值的方法。
@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
## add `driver` attribute to the class under test -->
if request.cls is not None:
request.cls.driver = driver
## <--
yield driver
print("Running one time tearDown")
现在您可以访问 driver
作为 TestClassDemo
中的 class 属性,就像您在示例中所做的那样(即 self.driver
应该有效)。
需要注意的是您的灯具必须使用 scope='class'
,否则 request
对象将不具有 cls
属性。
希望对您有所帮助!
更新
I have one more class, which object in need in the TestClassDemo and I need to pass the same driver instance to the class. Consider it as class ABC
如果没有更多上下文很难知道,但在我看来,您可以在实例化 driver
... 的同时实例化 ABC
对象oneTimeSetUp
夹具。例如...
@pytest.yield_fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
request.cls.abc = ABC(driver) # <-- here
yield driver
print("Running one time tearDown")
但是如果您只需要 ABC 实例进行一两次测试 class,下面是您可以如何在 class 定义中使用夹具...
@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class TestClassDemo(unittest.TestCase):
@pytest.fixture(autouse=True)
def build_abc(self, oneTimeSetUp): # <-- note the oneTimeSetup reference here
self.abc = ABC(self.driver)
def test_methodA(self):
self.driver.get("https://google.com")
self.abc.enterName("test")
print("Running method A")
def test_methodB(self):
self.abc.enterName("test")
print("Running method B")
我对第二个例子不是特别满意。第三种选择是有另一个 yield_fixture 或类似的,它与 oneTimeSetUp
和 returns 一个 ABC 实例完全分开,驱动程序已经包装。
哪种方式最适合您?不确定。你需要根据你正在使用的东西来决定。
应该为后代注意 pytest 固定装置只是糖和一点魔法。如果您发现它们很困难,则根本不需要使用它们。 pytest 很乐意执行 vanilla unittest 测试用例。
Also please explain in the answer what is the best way to use instead of yield driver instance.
这就是我的想法...
@pytest.fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
...请注意,这不会 return(或产生)驱动程序对象,这意味着将此夹具作为命名参数提供给 function/method 不再有用,如果您的所有测试用例都写成 classes(由您的示例建议),这应该没问题。
但是,如果您想将夹具用作命名参数,请不要这样做。
我有一个夹具 returns 值如下:
import pytest
@pytest.yield_fixture(scope="module")
def oneTimeSetUp(browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
yield driver
print("Running one time tearDown")
这个装置从另一个正在读取命令行选项的装置获取浏览器值。
然后我有一个测试class,其中我有多个测试方法,它们都希望使用相同的返回值驱动程序来继续测试。
import pytest
@pytest.mark.usefixtures("oneTimeSetUp")
class TestClassDemo():
def test_methodA(self):
# I would like to use the driver value here
# How could I do this?
# Something like this
self.driver.get("https://www.google.com")
self.driver.find_element(By.ID, "some id")
print("Running method A")
def test_methodB(self):
print("Running method B")
使用 self.driver 失败并显示错误消息
self = <test_class_demo.TestClassDemo object at 0x102fb6c18>
def test_methodA(self):
> self.driver.get("https://www.google.com")
E AttributeError: 'TestClassDemo' object has no attribute 'driver'
我知道我可以将夹具作为参数传递给每个我想使用它的方法,但这不是最好的方法,因为我在每个方法中都需要它并且应该可以将它传递给class 然后在所有测试方法中使用它。
使驱动程序对象可用于方法的最佳方法是什么?
编辑 1:
按照建议在 conftest.py 中创建夹具
@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
## add `driver` attribute to the class under test -->
if request.cls is not None:
request.cls.driver = driver
## <--
yield driver
print("Running one time tearDown")
我还有一个 class,TestClassDemo 中需要哪个对象,我需要将相同的驱动程序实例传递给 class。将其视为 class ABC
class ABC():
def __init(self, driver):
self.driver = driver
def enterName(self):
# Do something with driver instance
然后在TestClassDemo
@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class TestClassDemo(unittest.TestCase):
# I need to create an object of class ABC, so that I can use it here
# abc = ABC(self.driver)
@pytest.fixture(scope="class", autouse=True)
def setup(self):
self.abc = ABC(self.driver)
# I tried this, but it's not working
# This error message shows up
# AttributeError: 'TestClassDemo' object has no attribute 'driver'
def setup_module(self):
self.abc = ABC(self.driver)
# This also does not work
# Error message -> AttributeError: 'TestClassDemo' object has no attribute 'abc'
def test_methodA(self):
self.driver.get("https://google.com")
self.abc.enterName("test")
print("Running method A")
def test_methodB(self):
self.abc.enterName("test")
print("Running method B")
这个 abc 对象应该也可以在其他测试方法中使用。
所有这些 class 都在单独的模块中,我的意思是说在单独的 .py 文件中。
另外请在回答中说明什么是替代 yield 驱动程序实例的最佳使用方法。
编辑 2:
对于这个没有 yield 的例子,运行 oneTimeTearDown 的最佳方法是什么?在 yield
之后,我正在 运行 执行拆解步骤@pytest.fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
我也尝试使用 UnitTest class,但是当我使用 def setUpClass(cls) 时,我无法使用在 test_ 方法中实例化的对象。所以我无法弄清楚如何实现这一目标。
我还想从命令行提供命令行参数,例如浏览器,当我尝试 unittest 时,我不得不在每个 class 中编写命令行参数。我只想在一个地方提供它们,比如测试套件。所以 conftest 在这里帮助了我。
我有一个关于 Whosebug 的问题,但没有得到回复。你能看看那个吗? Python unittest passing arguments to parent test class
谢谢
谢谢
py.text unittest integration documentation 中概述了一项可能对您有所帮助的技术...使用内置的 request
夹具。否则,我不知道在不提供命名夹具作为方法参数的情况下访问夹具的 return 值的方法。
@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
## add `driver` attribute to the class under test -->
if request.cls is not None:
request.cls.driver = driver
## <--
yield driver
print("Running one time tearDown")
现在您可以访问 driver
作为 TestClassDemo
中的 class 属性,就像您在示例中所做的那样(即 self.driver
应该有效)。
需要注意的是您的灯具必须使用 scope='class'
,否则 request
对象将不具有 cls
属性。
希望对您有所帮助!
更新
I have one more class, which object in need in the TestClassDemo and I need to pass the same driver instance to the class. Consider it as class ABC
如果没有更多上下文很难知道,但在我看来,您可以在实例化 driver
... 的同时实例化 ABC
对象oneTimeSetUp
夹具。例如...
@pytest.yield_fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
request.cls.abc = ABC(driver) # <-- here
yield driver
print("Running one time tearDown")
但是如果您只需要 ABC 实例进行一两次测试 class,下面是您可以如何在 class 定义中使用夹具...
@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class TestClassDemo(unittest.TestCase):
@pytest.fixture(autouse=True)
def build_abc(self, oneTimeSetUp): # <-- note the oneTimeSetup reference here
self.abc = ABC(self.driver)
def test_methodA(self):
self.driver.get("https://google.com")
self.abc.enterName("test")
print("Running method A")
def test_methodB(self):
self.abc.enterName("test")
print("Running method B")
我对第二个例子不是特别满意。第三种选择是有另一个 yield_fixture 或类似的,它与 oneTimeSetUp
和 returns 一个 ABC 实例完全分开,驱动程序已经包装。
哪种方式最适合您?不确定。你需要根据你正在使用的东西来决定。
应该为后代注意 pytest 固定装置只是糖和一点魔法。如果您发现它们很困难,则根本不需要使用它们。 pytest 很乐意执行 vanilla unittest 测试用例。
Also please explain in the answer what is the best way to use instead of yield driver instance.
这就是我的想法...
@pytest.fixture(scope="class")
def oneTimeSetUp(request, browser):
print("Running one time setUp")
if browser == 'firefox':
driver = webdriver.Firefox()
driver.maximize_window()
driver.implicitly_wait(3)
print("Running tests on FF")
else:
driver = webdriver.Chrome()
print("Running tests on chrome")
if request.cls is not None:
request.cls.driver = driver
...请注意,这不会 return(或产生)驱动程序对象,这意味着将此夹具作为命名参数提供给 function/method 不再有用,如果您的所有测试用例都写成 classes(由您的示例建议),这应该没问题。
但是,如果您想将夹具用作命名参数,请不要这样做。