Pytest框架 — 07、Pytest的Fixture(部分前后置)(二)

打印 上一主题 下一主题

主题 925|帖子 925|积分 2775

目录

4、Fixture的相互调用

示例:
  1. import pytest
  2. # 第一层fixture
  3. @pytest.fixture()
  4. def fixture_1():
  5.     data = "fixture_1"
  6.     print("这是第一层fixture")
  7.     return data
  8. # 第二层fixture
  9. @pytest.fixture()
  10. def fixture_2(fixture_1):  # 在这里传递调用第一层fixture
  11.     print("这是第二层fixture")
  12. # 第三层fixture
  13. @pytest.fixture()
  14. @pytest.mark.usefixtures("fixture_1")  # 这种fixture相互调用方式不生效
  15. def fixture_3():
  16.     print("这是第三层fixture")
  17. # 测试类
  18. class TestClass:
  19.     def test_1(self, fixture_1):
  20.         print("调用第1层fixture,返回值为{}".format(fixture_1))
  21.     def test_2(self, fixture_2):
  22.         print("调用第2层fixture,返回值为{}".format(fixture_2))
  23.     def test_3(self, fixture_3):
  24.         print("调用第3层fixture")
  25. """
  26. 执行结果
  27. fixture/use_fixture_each_other.py::TestClass::test_1 这是第一层fixture
  28. 调用第1层fixture,返回值为fixture_1
  29. PASSED
  30. fixture/use_fixture_each_other.py::TestClass::test_2 这是第一层fixture
  31. 这是第二层fixture
  32. 调用第2层fixture,返回值为None
  33. PASSED
  34. fixture/use_fixture_each_other.py::TestClass::test_3 这是第三层fixture
  35. 调用第3层fixture
  36. PASSED
  37. """
复制代码
示例说明:

  • 在调用存在相互调用的fixture时,执行顺序由顶层fixture逐层向下执行(如示例test_2优先执行fixture_1再执行fixture_2)
  • 当调用存在相互调用的fixture时,直接被调用的fixture不会将自己接收到的返回值返回给调用方(如示例test_2不会接收到由fixture_1返回的值)
  • 相互调用fixture时不能使用pytest.mark.usefixture装饰器(如示例fixture_3)
5、Fixture复用

不同的测试函数可以请求相同的fixture,每个测试函数都会获得该fixture的各自结果。不同的测试函数不互相影响,这样可以保证每个测试函数都能得到干净一致的数据。
示例
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1():
  4.     return []
  5. def test_1(fixture_1):
  6.     fixture_1.append(0)
  7.     print(f"结果:{fixture_1}")
  8. def test_2(fixture_1):
  9.     fixture_1.append(9)
  10.     print(f"结果:{fixture_1}")
  11. """
  12. 执行结果
  13. fixture/reuse_fixture.py::test_1 结果:[0]
  14. PASSED
  15. fixture/reuse_fixture.py::test_2 结果:[9]
  16. PASSED
  17. """
复制代码
示例说明
由上面例子可以看出,两个测试函数都调用了fixture_1,但每次调用返回的结果是一样的,并不会因为test_1中fixture_1先添加了0而影响test_2调用的fixture_1返回的结果
6、Fixture缓存返回结果

同一个测试函数多次调用同一个fixture时,第一次执行该fixture函数之后,会把返回结果缓存起来,不会再次执行它们
示例:
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1():
  4.     print("执行fixture_1")
  5.     return "a"
  6. @pytest.fixture()
  7. def fixture_2():
  8.     print("执行fixture_2")
  9.     return []
  10. @pytest.fixture()
  11. def fixture_append(fixture_1, fixture_2):
  12.     print("执行fixture_append")
  13.     fixture_2.append(fixture_1)
  14. def test_fixture(fixture_append, fixture_2, fixture_1):
  15.     print("执行测试函数")
  16.     print(fixture_2)
  17. """
  18. 执行结果
  19. fixture/fixture_cache.py::test_fixture 执行fixture_1
  20. 执行fixture_2
  21. 执行fixture_append
  22. 执行测试函数
  23. ['a']
  24. PASSED
  25. """
复制代码
示例说明:
由上面例子可以看出在fixture函数fixture_append中,fixture_1第一次被请求返回字母a,fixture_2被第二次被请求返回空列表,在测试函数test_fixture中fixture_2第二次被请求,但返回结果不是不是空列表,而是['a']。如果同一个fixture在同一个测试函数中每次都去请求,那么必然返回的是空列表。
7、Fixture的后置处理

前面的案例都是加了前置处理,相当于setup(),后置teardown()在fixture中是可以通过yield关键字和addfinalizer关键字来实现
(一)使用yield关键字实现后置


  • 示例
  1. import pytest
  2. @pytest.fixture(autouse=True)
  3. def fixture_3():
  4.     print("这是一个前置处理")
  5.     yield
  6.     print("这是一个后置处理")
  7. def testcase_1(fixture_3):
  8.     print("这是测试用例1")
  9. def testcase_2(fixture_3):
  10.     print("这是测试用例2")
  11. """
  12. 执行结果
  13. fixture/use_fixture_3.py::testcase_1 这是一个前置处理
  14. 这是测试用例1
  15. PASSED这是一个后置处理
  16. fixture/use_fixture_3.py::testcase_2 这是一个前置处理
  17. 这是测试用例2
  18. PASSED这是一个后置处理
  19. """
复制代码

  • 执行顺序
    在前置处理中会根据fixture函数之间的线性关系顺序调用的,后置处理顺序会反过来
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1():
  4.     print("这是fixture_1")
  5.     return 1
  6. @pytest.fixture()
  7. def fixture_2(fixture_1):
  8.     print("这是fixture_2的【前置】")
  9.     yield 2
  10.     print("这是fixture_2的【后置】")
  11. @pytest.fixture()
  12. def fixture_add(fixture_1, fixture_2):
  13.     print("这是fixture_add的【前置】")
  14.     yield fixture_1 + fixture_2
  15.     print('这是fixture_add的【后置】')
  16. def test_fixture(fixture_2, fixture_add):
  17.     print("这是测试函数")
  18.     assert fixture_add == 3
  19. """
  20. 执行结果
  21. fixture/yiled_order.py::test_fixture 这是fixture_1
  22. 这是fixture_2的【前置】
  23. 这是fixture_add的【前置】
  24. 这是测试函数
  25. PASSED这是fixture_add的【后置】
  26. 这是fixture_2的【后置】
  27. """
复制代码
(二)使用addfinalizer关键字实现后置


  • request.addfinalizer把函数变成终结器实现后置处理
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1(request):
  4.     print("这是fixture_1的【前置】处理")
  5.     def addfinalizer_demo():
  6.         print("这是fixture_1的【后置】处理")
  7.     # 注册后置处理
  8.     request.addfinalizer(addfinalizer_demo)
  9. def test_fixture(fixture_1):
  10.     print("===这是测试函数===")
  11. """
  12. 执行结果
  13. fixture/use_addfinalizer.py::test_fixture 这是fixture_1的【前置】处理
  14. ===这是测试函数===
  15. PASSED这是fixture_1的【后置】处理
  16. """
复制代码

  • request.addfinalizer注册多个终结器函数
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1(request):
  4.     print("这是fixture_1的【前置】处理")
  5.     def addfinalizer_demo_1():
  6.         print("这是fixture_1的【后置】处理1")
  7.     def addfinalizer_demo_2():
  8.         print("这是fixture_2的【后置】处理2")
  9.     # 将多个后置处理函数注册成终结函数
  10.     request.addfinalizer(addfinalizer_demo_1)
  11.     request.addfinalizer(addfinalizer_demo_2)
  12. def test_fixture(fixture_1):
  13.     print("=====这是测试函数=====")
  14. """
  15. 执行结果
  16. fixture/use_more_addfinalizer.py::test_fixture 这是fixture_1的【前置】处理
  17. =====这是测试函数=====
  18. PASSED这是fixture_2的【后置】处理2
  19. 这是fixture_1的【后置】处理1
  20. """
复制代码

  • 执行顺序
    由上面注册多个终结器函数示例中可以看到,使用addfinalizer关键字处理后置函数的执行顺序与注册顺序是反的
(三)yield和addfinalizer的区别

区别在于如果fixture中前置出现异常,yield后置不会执行,而addfinalizer后置会执行。

  • 使用yield
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_yield():
  4.     print("这是fixture_yield前置")
  5.     res = 21/0
  6.     yield
  7.     print("这是fixtue_yield后置")
  8. def test_fixture(fixture_yield):
  9.     print("这是测试函数")
  10. """
  11. 执行结果
  12. yield_error.py::test_fixture ERROR                                       [100%]这是fixture_yield前置
  13. test setup failed
  14. @pytest.fixture()
  15.     def fixture_yield():
  16.         print("这是fixture_yield前置")
  17. >       res = 21/0
  18. E       ZeroDivisionError: division by zero
  19. yield_error.py:12: ZeroDivisionError
  20. """
复制代码

  • 使用addfinalizer
  1. import pytest
  2. @pytest.fixture()
  3. def fixture_1(request):
  4.     print("这是fixture_1前置")
  5.     def addfinalizer_demo():
  6.         print("这是fixture_1后置")
  7.     request.addfinalizer(addfinalizer_demo)
  8.     res = 21/0
  9. def test_fixture(fixture_1):
  10.     print("这是测试函数")
  11. """
  12. 执行结果
  13. addfinalizer_error.py::test_fixture ERROR                                [100%]这是fixture_1前置
  14. test setup failed
  15. request = <SubRequest 'fixture_1' for <Function test_fixture>>
  16.     @pytest.fixture()
  17.     def fixture_1(request):
  18.         print("这是fixture_1前置")
  19.    
  20.         def addfinalizer_demo():
  21.             print("这是fixture_1后置")
  22.         request.addfinalizer(addfinalizer_demo)
  23. >       res = 21/0
  24. E       ZeroDivisionError: division by zero
  25. addfinalizer_error.py:16: ZeroDivisionError
  26. 这是fixture_1后置
  27. """
复制代码
从上面yield和addfinalizer的示例中可以看出yield前置中出现异常,后置处理没有被执行,而addfinalizer的前置中出现异常,并没有影响后置的执行。
注意: 使用addfinalizer一定是后置函数注册成功后出现异常才不会受影响。
参考:https://zhuanlan.zhihu.com/p/355285675

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表