通过一个例子理解pytest的fixture的使用

需求

  • 希望编写登陆web后做一些操作的测试用例,使用pytest框架
  • 具体测试用例执行前,需要先拿到web的token,这个获取token的动作只执行一次

例一

  • 先上测试用例代码

    admin@pc-1:~$ cat my_test.py
    import pytest

    class TestWebLogin:
    @pytest.fixture(scope='function', autouse=True)
    def setup_teardown(self):
    # setup
    print('@@@@@@@@@@@@@@@@@@@@@get token')
    #toke = login_web()
    self.token = 'abc'

    复制代码
          yield  # 运行测试用例
    
          # teardown
    
      def test_case1(self):
          # 使用 self.app 进行测试
          assert self.token is not None
          # 其他测试逻辑
    
      def test_case2(self):
          # 使用 self.app 进行测试
          assert self.token is not None
          # 其他测试逻辑

    admin@pc-1:~ admin@pc-1:~
    admin@pc-1:~$ pytest -sv my_test.py
    ================================================================= test session starts ==================================================================
    platform linux -- Python 3.8.10, pytest-7.4.0, pluggy-1.2.0 -- /usr/bin/python3
    cachedir: .pytest_cache
    rootdir: /home/centec
    plugins: dash-2.14.1, solara-1.21.0, anyio-4.0.0
    collected 2 items

    my_test.py::TestWebLogin::test_case1 @@@@@@@@@@@@@@@@@@@@@get token
    PASSED
    my_test.py::TestWebLogin::test_case2 @@@@@@@@@@@@@@@@@@@@@get token
    PASSED

    ================================================================== 2 passed in 0.01s ===================================================================
    admin@pc-1:~$

  • 解释

    • class TestWebLogin里每个test_开头的function就是一个测试用例
    • setup_teardown函数是实现login和logout,yield之前是setup,yield之后是teardown
  • 运行结果是在每个test case前都执行了一遍获取token的动作(scope='function')

例二

  • 希望所有的case只在执行第一个的时候获取一下token,后面的case直接使用token即可

  • 尝试将fixture的scope从fuction改为class,并执行

    admin@pc-1:~$ cat my_test.py
    import pytest

    class TestWebLogin:
    @pytest.fixture(scope='class', autouse=True)
    def setup_teardown(self):
    # setup
    print('@@@@@@@@@@@@@@@@@@@@@get token')
    #toke = login_web()
    self.token = 'abc'

    复制代码
          yield  # 运行测试用例
    
          # teardown
    
      def test_case1(self):
          # 使用 self.app 进行测试
          assert self.token is not None
          # 其他测试逻辑
    
      def test_case2(self):
          # 使用 self.app 进行测试
          assert self.token is not None
          # 其他测试逻辑

    admin@pc-1:~ admin@pc-1:~ pytest -sv my_test.py
    ================================================================= test session starts ==================================================================
    platform linux -- Python 3.8.10, pytest-7.4.0, pluggy-1.2.0 -- /usr/bin/python3
    cachedir: .pytest_cache
    rootdir: /home/centec
    plugins: dash-2.14.1, solara-1.21.0, anyio-4.0.0
    collected 2 items

    my_test.py::TestWebLogin::test_case1 @@@@@@@@@@@@@@@@@@@@@get token
    FAILED
    my_test.py::TestWebLogin::test_case2 FAILED

    ======================================================================= FAILURES =======================================================================
    _______________________________________________________________ TestWebLogin.test_case1 ________________________________________________________________

    self = <my_test.TestWebLogin object at 0x7f909a307cd0>

    复制代码
      def test_case1(self):
          # 使用 self.app 进行测试
    复制代码
      assert self.token is not None

    E AttributeError: 'TestWebLogin' object has no attribute 'token'

    my_test.py:17: AttributeError
    _______________________________________________________________ TestWebLogin.test_case2 ________________________________________________________________

    self = <my_test.TestWebLogin object at 0x7f909a307610>

    复制代码
      def test_case2(self):
          # 使用 self.app 进行测试
    复制代码
      assert self.token is not None

    E AttributeError: 'TestWebLogin' object has no attribute 'token'

    my_test.py:22: AttributeError
    =============================================================== short test summary info ================================================================
    FAILED my_test.py::TestWebLogin::test_case1 - AttributeError: 'TestWebLogin' object has no attribute 'token'
    FAILED my_test.py::TestWebLogin::test_case2 - AttributeError: 'TestWebLogin' object has no attribute 'token'
    ================================================================== 2 failed in 0.14s ===================================================================
    admin@pc-1:~$

  • 意料之外的是,在setup_teardown中明明已经给self.token赋值了,但是同在一个class下,其它的测试用例却看不到self.token!!!

  • pytest的test class是比较特殊的,不能通过self.xxx来传递值,只能通过fixture

  • 于是有了下面的改进

例三

  • case修改如下

    admin@pc-1:~$ cat my_test.py
    import pytest

    class TestWebLogin:
    @pytest.fixture(scope='class', autouse=False)
    def setup_teardown(self):
    # setup
    print('@@@@@@@@@@@@@@@@@@@@@get token')
    #toke = login_web()
    token = 'abc'

    复制代码
          yield token # 运行测试用例
    
          # teardown
    
      def test_case1(self, setup_teardown):
          token = setup_teardown
          assert token is not None
          print(f'toke={token}')
          # 其他测试逻辑
    
      def test_case2(self, setup_teardown):
          token = setup_teardown
          assert token is not None
          print(f'token={token}')
          # 其他测试逻辑

    admin@pc-1:~ admin@pc-1:~
    admin@pc-1:~ admin@pc-1:~ pytest -sv my_test.py
    ================================================================= test session starts ==================================================================
    platform linux -- Python 3.8.10, pytest-7.4.0, pluggy-1.2.0 -- /usr/bin/python3
    cachedir: .pytest_cache
    rootdir: /home/centec
    plugins: dash-2.14.1, solara-1.21.0, anyio-4.0.0
    collected 2 items

    my_test.py::TestWebLogin::test_case1 @@@@@@@@@@@@@@@@@@@@@get token
    toke=abc
    PASSED
    my_test.py::TestWebLogin::test_case2 token=abc
    PASSED

    ================================================================== 2 passed in 0.01s ===================================================================
    admin@pc-1:~$

  • 修改点包括

    • fixture的scope为class,表示在TestWebLogin中只会执行一次
    • fixture的autouse赋值为False,相当于需要显式调用,不会自动运行
    • 所有的赋值就没有必要加self了
    • setup_teardown的yield后面加token,类似于return token
    • 后面的testcase 将setup_teardown作为一个参数传入,然后进行显式的赋值
  • 从执行结果来看,获取token只做了一次,后续所有的case都直接使用这个token了

相关推荐
FINE!(正在努力!)2 天前
PyTest框架学习
学习·pytest
程序员杰哥2 天前
接口自动化测试之pytest 运行方式及前置后置封装
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·pytest
测试老哥3 天前
Pytest+Selenium UI自动化测试实战实例
自动化测试·软件测试·python·selenium·测试工具·ui·pytest
水银嘻嘻3 天前
07 APP 自动化- appium+pytest+allure框架封装
python·appium·自动化·pytest
天才测试猿3 天前
接口自动化测试之pytest接口关联框架封装
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·pytest
not coder4 天前
Pytest Fixture 详解
数据库·pytest
not coder5 天前
pytest 常见问题解答 (FAQ)
开发语言·python·pytest
程序员的世界你不懂5 天前
(1)pytest简介和环境准备
pytest
not coder5 天前
Pytest Fixture 是什么?
数据库·oracle·pytest
Tester_孙大壮5 天前
pytest中的元类思想与实战应用
pytest