【问题标题】:How do i make the pytest driver instance available in my testcase如何使 pytest 驱动程序实例在我的测试用例中可用
【发布时间】:2018-08-04 04:26:02
【问题描述】:

我正在尝试使用 Python、Pytest 构建一个基于硒的自动化框架。 我的目的是通过在 conftest.py 中对其进行初始化并使其在所有测试用例中可用,从而在类级别创建一个驱动程序实例,这样用户就无需在每个测试用例中创建驱动程序实例。

conftest.py 中的驱动实例:

@pytest.fixture(scope="class")
def get_driver(request):
    from selenium import webdriver
    driver = webdriver.Chrome()
    request.cls.driver = driver
    yield
    driver.quit()

BaseTestCase 类如下所示:

@pytest.mark.usefixtures("get_driver")
class BaseTestCase(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        super(BaseTestCase, self).__init__(*args, **kwargs)

    @classmethod
    def setUpClass(cls):
        if hasattr(super(BaseTestCase, cls), "setUpClass"):
            super(BaseTestCase, cls).setUpClass()

我的测试用例如下:

from ..pages.google import Google

class Test_Google_Page(BaseTestCase):

    @classmethod
    def setUpClass(self):
        self.page = Google(self.driver, "https://www.google.com/")

我的 Google 页面扩展到 BasePage,如下所示:

class BasePage(object):
    def __init__(self, driver, url=None, root_element = 'body'):
        super(BasePage, self).__init__()

        self.driver = driver
        self._root_element = root_element
        self.driver.set_script_timeout(script_timeout)

当我执行我的测试用例时,我收到以下错误:

    @classmethod
    def setUpClass(self):
>       driver = self.driver
E       AttributeError: type object 'Test_Google_Page' has no attribute 'driver'

如何通过简单地调用 self.driver 使驱动程序实例在我的测试用例中可用?

【问题讨论】:

    标签: python selenium selenium-webdriver pytest


    【解决方案1】:

    类作用域的fixtures在setUpClass类方法之后执行,所以当Test_Google_Page.setUpClass被执行时,get_driver还没有运行。查看执行顺序:

    import unittest
    import pytest
    
    
    @pytest.fixture(scope='class')
    def fixture_class_scoped(request):
        print(f'{request.cls.__name__}::fixture_class_scoped()')
    
    
    @pytest.mark.usefixtures('fixture_class_scoped')
    class TestCls(unittest.TestCase):
    
        @classmethod
        def setUpClass(cls):
            print(f'{cls.__name__}::setUpClass()')
    
        def setUp(self):
            print(f'{self.__class__.__name__}::setUp()')
    
        @pytest.fixture()
        def fixture_instance_scoped(self):
            print(f'{self.__class__.__name__}::fixture_instance_scoped()')
    
        @pytest.mark.usefixtures('fixture_instance_scoped')
        def test_bar(self):
            print(f'{self.__class__.__name__}::test_bar()')
            assert True
    

    当运行测试时,例如pytest -sv,输出结果:

    TestCls::setUpClass()
    TestCls::fixture_class_scoped()
    TestCls::fixture_instance_scoped()
    TestCls::setUp()
    TestCls::test_bar()
    

    所以解决方案是将代码从 setUpClass 移动到例如setUp:

    class Test_Google_Page(BaseTestCase):
    
        def setUp(self):
            self.page = Google(self.driver, "https://www.google.com/")
    

    恐怕我可能不会使用 setUp,因为在我的大部分类文件中,我有多个测试用例,我只想在 setUpClass 中进行一次设置,而不是在每次调用任何测试方法之前启动。

    然后我会将代码从 setUpClass 移动到另一个类范围的夹具:

    import pytest
    
    @pytest.mark.usefixtures('get_driver')
    @pytest.fixture(scope='class')
    def init_google_page(request):
        request.cls.page = Google(request.cls.driver, 
                                  "https://www.google.com/")
    
    
    @pytest.mark.usefixtures('init_google_page')
    class Test_Google_Page(BaseTestCase):
        ...
    

    以前的setUpClass 现在是init_google_page 固定装置,它将在get_driver 之后调用(因为pytest.mark.usefixtures('get_driver'))。

    【讨论】:

    • 感谢您抽出宝贵时间@hoefling,恐怕我可能不会使用 setUp,因为在我的大部分类文件中,我有多个测试用例,我只想在 setUpClass 中进行一次设置,而不是在每次调用任何测试方法之前。您认为将夹具范围更改为会话会有所帮助吗?
    • 然后我会将代码从setUpClass 移出另一个类范围的夹具。有关示例,请参阅更新的答案。
    猜你喜欢
    • 2022-10-15
    • 1970-01-01
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    相关资源
    最近更新 更多