Pytest-Fixture妙用

1 每次测试可以多次请求fixture(缓存返回值)

原文:Fixtures can also be requested more than once during the same test, and pytest won’t execute them again for that test.

This means we can request fixtures in multiple fixtures that are dependent on them (and even again in the test itself)

without those fixtures being executed more than once.

意思就是在一个test用例中可以对同一个fixture进行多次请求,pytest仅会执行一次,下面看个例子。

 1 import pytest
 2 
 3 
 4 # Arrange
 5 @pytest.fixture
 6 def first_entry():
 7     return "a"
 8 
 9 
10 # Arrange
11 @pytest.fixture
12 def order():
13     return []
14 
15 
16 # Act
17 @pytest.fixture
18 def append_first(order, first_entry):
19     return order.append(first_entry)
20 
21 
22 def test_string_only(append_first, order, first_entry):
23     # Assert
24     assert order == [first_entry]

如果在一个 test 用例中每请求一次fixture时,都将该 fixture 执行一遍,那么这个测试会失败。因为 append_first 和 test_string_only 都会将 order 视为一个空列表,

但是 pytest 会在第一次访问 order 时缓存 order 的返回值,在整个 test 用例和 append_first 中都引用相同的 order 对象,因此 append_first 里面是对该 order 对象进行的操作。

可以用 --setup-show 参数观察 fixture 的访问过程,可以看到 order 仅被执行一次

2 直接添加终结器addfinalizer

yield与addfinalizer的区别

1. addfinalizer可以注册多个终结函数,但是要注意的是执行顺序,与注册的顺序相反。

2. 当setUp的代码执行错误,addfinalizer依旧会执行,而yield是不会执行teardown代码的。

1 @pytest.fixture
2 def receiving_user(mail_admin, request):
3     user = mail_admin.create_user()
4     
5     def delete_user():
6         mail_admin.delete_user(user)
7     
8     request.addfinalizer(delete_user)
9     return user

3 Fixture 可以内省访问测试上下文

fixture 函数可以接受 request 对象内省“请求”测试函数、类或模块上下文

例:从使用fixture的测试模块中读取一个可选的服务器URL

 1 # content of conftest.py
 2 import pytest
 3 import smtplib
 4 
 5 
 6 @pytest.fixture(scope="module")
 7 def smtp_connection(request):
 8     server = getattr(request.module, "smtpserver","smtp.gmail.com")
 9     smtp_connection = smtplib.SMTP(server, 587, timeout=5)
10     yield smtp_connection
11     print("finalizing {} ({})".format(smtp_connection, server))
12     smtp_connection.close()
1 # content of test_anothersmtp.py
2 
3 smtpserver = "mail.python.org"  # will be read by smtp fixture
4 
5 
6 def test_showhelo(smtp_connection):
7     assert 0, smtp_connection.helo()

可以观察到,一般是先执行 conftest 中的 fixture,然后再执行测试文件 test_anothersmtp.py,但是该 fixture 中可以内省访问测试文件中的 smtpserver 属性

 4 使用marker将数据传输到fixture

使用 request 对象时,fixture还可以访问应用于测试函数的标记marker。这对于将数据从测试传递到 fixture 中非常有用

 1 import pytest
 2 
 3 
 4 @pytest.fixture
 5 def fixt(request):
 6     marker = request.node.get_closest_marker("fixt_data")
 7     if marker is None:
 8         # Handle missing marker in some way...
 9         data = None
10     else:
11         data = marker.args[0]
12 
13     # Do something with the data
14     return data
15 
16 
17 @pytest.mark.fixt_data(43)
18 def test_fixt(fixt):
19     assert fixt == 43
20 
21 if __name__ == '__main__':
22     pytest.main(['-v', 'test_fixture.py'])

5 对参数化fixture使用marks

pytest.param() 可用于在参数化 fixture 的值集中应用标记,方法与它们可用于的方法相同 @pytest.mark.parametrize

 1 # content of test_fixture_marks.py
 2 import pytest
 3 
 4 
 5 @pytest.fixture(params=[0, 1, pytest.param(2,marks=pytest.mark.skip)])
 6 def data_set(request):
 7     return request.param
 8 
 9 
10 def test_data(data_set):
11     pass

运行此测试将跳过 参数值为2 的调用

$ pytest test_fixture_marks.py -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collecting ... collected 3 items

test_fixture_marks.py::test_data[0] PASSED                           [ 33%]
test_fixture_marks.py::test_data[1] PASSED                           [ 66%]
test_fixture_marks.py::test_data[2] SKIPPED (unconditional skip)     [100%]

======================= 2 passed, 1 skipped in 0.12s =======================

 

 

 

 

 

 

 

 

posted on 2022-07-05 21:59  ZouYus  阅读(60)  评论(0编辑  收藏  举报