通过一个例子理解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了

相关推荐
qq_4337169521 小时前
测试分层:减少对全链路回归依赖的探索!
自动化测试·软件测试·功能测试·测试工具·回归·pytest·postman
开心呆哥2 天前
【Android Wi-Fi 操作命令指南】
android·python·pytest
小码哥说测试4 天前
测试分层:减少对全链路回归依赖的探索!
自动化测试·软件测试·人工智能·测试工具·appium·pytest·postman
帅得不敢出门5 天前
Python+Appium+Pytest+Allure自动化测试框架-安装篇
python·appium·自动化·pytest·测试·allure
blues_C5 天前
Pytest-Bdd-Playwright 系列教程(5):仅执行测试用例的收集阶段
自动化测试·测试用例·pytest·bdd
帅得不敢出门7 天前
Python+Appium+Pytest+Allure自动化测试框架-代码篇
python·appium·自动化·pytest·测试·allure
qq_433716958 天前
接口测试 —— Postman 变量了解一下!
自动化测试·软件测试·jmeter·单元测试·pytest·接口测试·压力测试
彳亍2618 天前
【Python单元测试】pytest框架单元测试 配置 命令行操作 测试报告 覆盖率
python·单元测试·pytest
鹿鸣悠悠8 天前
pytest脚本常用的执行命令
pytest