代码之家  ›  专栏  ›  技术社区  ›  Sun Shine

pytest->如何在类下的测试方法中使用fixturn值

  •  9
  • Sun Shine  · 技术社区  · 9 年前

    我有一个fixture,它返回如下值:

    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")
    

    该装置从另一个正在读取命令行选项的装置获取浏览器值。

    然后我有一个测试类,其中有多个测试方法,它们都希望使用相同的返回值驱动程序来继续测试。

    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 = <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'
    

    我知道我可以将fixture作为参数传递给我想使用它的每个方法,但这不是最好的方法,因为我在每个方法中都需要它,应该可以将它传递给类,然后在所有测试方法中使用它。

    我可以使驱动程序对象对方法可用的最佳方式是什么?

    编辑1:

    在conftest中创建了fixture。像建议的那样

    @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")
    

    我还有一个类,它是TestClassDemo中需要的对象,我需要将相同的驱动程序实例传递给该类。将其视为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对象也应该可以在其他test_methods中使用。

    所有这些类都在单独的模块中,我的意思是说在单独的.py文件中。

    另外,请在回答中解释什么是最好的使用方法,而不是给出驱动程序实例。

    编辑2:

    对于这个没有收益的例子,运行oneTimeTearDown的最佳方式是什么?我在收益率后运行了拆卸步骤

    @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类,但当我使用def setUpClass(cls)时,我无法使用test_methods中实例化的对象。所以我不知道如何实现这一点。

    我还想从命令行提供诸如浏览器之类的命令行参数,当我尝试unittest时,我必须在每个类中编写命令行参数。我只想在一个地方提供它们,比如一个测试套件。所以conftest在这里帮了我。

    我有一个关于stackoverflow的问题,但没有得到回应。你能也看看吗? Python unittest passing arguments to parent test class

    谢谢

    谢谢

    1 回复  |  直到 8 年前
        1
  •  8
  •   Marty    9 年前

    py.text unittest integration documentation 这可能会对您有所帮助……使用内置 request 固定装置否则,我不知道如何在不将命名fixture作为方法参数提供的情况下访问fixtures的返回值。

    @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 ,如您在示例中所述(即。 self.driver 应该有效)。

    警告是您的固定装置必须使用 scope='class' ,否则为 要求 对象不会拥有 cls 属性

    我希望这有帮助!


    更新

    我还有一个类,它是TestClassDemo中需要的对象,我需要将相同的驱动程序实例传递给该类。将其视为ABC类

    没有更多的上下文很难知道,但在我看来,您可能可以通过实例化 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实例,那么可以在类定义中使用fixture。。。

    @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或类似的,它与 一次性设置 并返回已包装驱动程序的ABC实例。

    哪条路最适合你?不确定。你需要根据你在做什么来决定。

    值得后人注意的是,pytest装置只是糖和一点魔法。如果你觉得很难,你根本不需要使用它们。pytest很乐意执行vanilla unittest TestCases。


    另外,请在回答中解释什么是最好的使用方法,而不是给出驱动程序实例。

    这是我的想法。。。

    @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
    

    …请注意,这不会返回(或产生)驱动程序对象,这意味着将此fixture作为命名参数提供给函数/方法不再有用,如果您的所有测试用例都是作为类编写的(示例中建议的),这应该很好。

    但是,如果要将fixture用作命名参数,请不要这样做。