pytest合集(6)— Fixture夹具
简单来说,pytest中的夹具就是用来实现测试前的环境准备,提供测试数据和测试后的环境清理动作。类似于unittest框架里的setup(前置处理),teardown(后置处理)。常用在测试环境搭建和销毁,测试数据的共享,登录登出操作,数据库连接和关闭,浏览器打开关闭等操作。使用@pytest.fixture装饰器将一个函数标记成夹具,可以在测试用例文件中定义夹具,也可以在conftest.py文
一、关于夹具
1、夹具介绍
简单来说,pytest中的夹具就是用来实现测试前的环境准备,提供测试数据和测试后的环境清理动作。类似于unittest框架里的setup(前置处理),teardown(后置处理)。
常用在测试环境搭建和销毁,测试数据的共享,登录登出操作,数据库连接和关闭,浏览器打开关闭等操作。
2、夹具特点
- fixture固定装置,也叫夹具,下文都称呼为夹具。
- 使用 @pytest.fixture 可以将一个函数标记成夹具。
- 夹具本质上是函数,测试函数显示调用来使用夹具。
- 夹具的名称不要用test开头。
- 夹具可以定义在conftest.py文件中。
- 可以在测试函数,测试类,模块,甚至session会话级别使用夹具。
- 测试函数可以使用一个或者多个夹具,夹具也可以使用夹具,这才是fixture夹具功能真正强大的地方。
- pytest查找夹具的顺序:测试类>>测试模块>> conftest.py 文件>>内置插件和第三方插件。
3、夹具的简单使用
新建 test_fixture.py 文件如下:
import pytest@pytest.fixture def myfixture(): print("this is myfixture") return True def test_one(myfixture): assert myfixture is True
运行命令:pytest test_fixture.py -vs
(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>pytest test_fixture.py -vs
=================================== test session starts ===================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}rootdir: C:\Users\057776\PycharmProjects\pytest-demo\testfixture
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 1 itemtest_fixture.py::test_one this is myfixture PASSED
=================================== 1 passed in 0.03s ===================================
(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>
说明:
测试函数test_one 使用myfixture作为参数,pytest 运行时候,会先查找并运行它参数的同名夹具myfixture,打印出了"this is my fixture",并且捕获到了夹具的返回值 True。
夹具执行过程(官网说明):
在基本层面上,测试函数通过将它们声明为参数来请求它们所需的夹具。
当 pytest 开始运行测试时,它会查看该测试函数签名中的参数,然后搜索与这些参数具有相同名称的夹具。一旦 pytest 找到它们,它就会运行这些固定装置,捕获它们返回的内容(如果有的话),并将这些对象作为参数传递给测试函数。
二、定义夹具
使用@pytest.fixture装饰器可以将测试函数标记成夹具,可以在测试用例文件中定义夹具,也可以在conftest.py文件中定义夹具,推荐使用conftest.py文件定义夹具。
1、fixture参数
fixture它有5个参数,分别是scope, params, autouse, ids, name。
@
fixture
(fixture_function=None, *, scope='function', params=None, autouse=False, ids=None, name=None)
scope:
作用域参数,他有4个级别分别是 function,class,module,session,默认function。
- function:函数级别,默认范围,夹具在测试结束时被销毁。
- class:类级别,夹具在类中最后一个测试结束时被销毁。
- module:模块级别,夹具在.py文件中最后一个测试结束时被销毁
- session:会话级别,夹具在测试会话结束时被销毁。
params:
一个可选的参数列表,默认值为None,可以用来实现 参数化,参数化的时候这里需要用到一个参数request,使用“request.param”来接受请求参数列表,进而实现参数化。
ids:
字符串列表,与params配合使用,如果没有提供 id,它们将从参数中自动生成。
autouse:
默认值False ,需要显式引用来激活夹具。如果为TRUE,则所有测试函数都可以使用该夹具(慎用)。
name:
夹具名称默认取的是被定义成夹具的函数名称,可以修改这个参数来修改夹具名称,需要注意的是,只能使用修改后的夹具名,不能使用原来的夹具函数名。
2、yield和return的区别
夹具中可以使用return,yield关键字为测试函数提供值,推荐使用yield关键字,他们的区别如下:
- yield返回值后,后面的代码还会继续运行
- return返回值后,后面的代码不会继续运行
三、使用夹具
1、function函数级别,将夹具名作为测试函数参数的入参(显示调用)
新建conftest.py配置文件如下,定义一个function级别的夹具。
import pytest
@pytest.fixture(scope='function')
def myfixture_function():
print("开始加载function级别夹具")
yield 100
print("开始退出function级别夹具")
修改test_fixture.py文件如下:
def test_one(myfixture_function):
assert myfixture_function == 100
文件目录结构如下:
进入testfixture目录,运行命令:pytest -vs
Microsoft Windows [版本 10.0.19044.1889]
(c) Microsoft Corporation。保留所有权利。(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>pytest -vs
=================================== test session starts ===================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}rootdir: C:\Users\057776\PycharmProjects\pytest-demo\testfixture
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 1 itemtest_fixture.py::test_one 开始加载function级别夹具
PASSED开始退出function级别夹具
=================================== 1 passed in 0.05s ===================================(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>
可知,function级别的夹具在显示调用该夹具的测试用例执行完后销毁。
2、class类级别,使用mark标记装饰器@pytest.mark.userfixtures
语法糖:
pytest.mark.usefixtures(*args)
*args – The names of the fixture to use, as strings.
看到装饰器的参数就能晓得,usefixtures可以和一个或者多个fixture配合使用。
修改conftest.py配置文件如下,新增一个class级别的夹具。
import pytest
@pytest.fixture(scope='function')
def myfixture_function():
print("开始加载function级别夹具")
yield 100
print("开始退出function级别夹具")
@pytest.fixture(scope='class')
def myfixture_class():
print("开始加载class级别夹具")
yield 200
print("开始退出class级别夹具")
修改test_fixture.py文件如下:
import pytest
def test_one(myfixture_function):
assert myfixture_function == 100
@pytest.mark.usefixtures('myfixture_class')
class TestFixture:
def test_two(self, myfixture_function):
assert myfixture_function == 100
def test_three(self):
pass
进入testfixture目录,运行命令:pytest -vs
(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>pytest -vs
=================================== test session starts ===================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}rootdir: C:\Users\057776\PycharmProjects\pytest-demo\testfixture
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 3 itemstest_fixture.py::test_one 开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_two 开始加载class级别夹具
开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_three PASSED开始退出class级别夹具
=================================== 3 passed in 0.07s ===================================(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>
可知,class级别的夹具在测试类中所有测试用例执行完后销毁。
3、module模块级别,使用pytestmark
修改conftest.py配置文件如下,新增一个module级别的夹具。
import pytest
@pytest.fixture(scope='function')
def myfixture_function():
print("开始加载function级别夹具")
yield 100
print("开始退出function级别夹具")
@pytest.fixture(scope='class')
def myfixture_class():
print("开始加载class级别夹具")
yield 200
print("开始退出class级别夹具")
@pytest.fixture(scope='module')
def myfixture_module():
print("开始加载module级别夹具")
yield 300
print("开始退出module级别夹具")
修改test_fixture.py文件如下:
import pytest
pytestmark = pytest.mark.usefixtures('myfixture_module')
def test_one(myfixture_function):
assert myfixture_function == 100
@pytest.mark.usefixtures('myfixture_class')
class TestFixture:
def test_two(self, myfixture_function):
assert myfixture_function == 100
def test_three(self):
pass
进入testfixture目录,运行命令:pytest -vs
(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>pytest -vs
=================================== test session starts ===================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}rootdir: C:\Users\057776\PycharmProjects\pytest-demo\testfixture
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 3 itemstest_fixture.py::test_one 开始加载module级别夹具
开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_two 开始加载class级别夹具
开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_three PASSED开始退出class级别夹具
开始退出module级别夹具
=================================== 3 passed in 0.08s ===================================(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>
可知,module级别的夹具在测试文件中所有用例执行完成后销毁。
4、session会话级别,autouse=True
修改conftest.py配置文件如下,新增一个session级别的夹具。这里需要注意参数 autouse=True会话级别的夹具才能生效。
import pytest
@pytest.fixture(scope='function')
def myfixture_function():
print("开始加载function级别夹具")
yield 100
print("开始退出function级别夹具")
@pytest.fixture(scope='class')
def myfixture_class():
print("开始加载class级别夹具")
yield 200
print("开始退出class级别夹具")
@pytest.fixture(scope='module')
def myfixture_module():
print("开始加载module级别夹具")
yield 300
print("开始退出module级别夹具")
@pytest.fixture(scope='session', autouse=True)
def myfixture_session():
print("开始加载session级别夹具")
yield 400
print("开始退出session级别夹具")
在testfixture目录中新建test_sample.py文件如下:
def test_session(myfixture_function):
assert myfixture_function == 100
进入testfixture目录,运行命令:pytest -vs
(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>pytest -vs
=================================== test session starts ===================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}rootdir: C:\Users\057776\PycharmProjects\pytest-demo\testfixture
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 4 itemstest_fixture.py::test_one 开始加载session级别夹具
开始加载module级别夹具
开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_two 开始加载class级别夹具
开始加载function级别夹具
PASSED开始退出function级别夹具test_fixture.py::TestFixture::test_three PASSED开始退出class级别夹具
开始退出module级别夹具test_sample.py::test_session 开始加载function级别夹具
PASSED开始退出function级别夹具
开始退出session级别夹具
=================================== 4 passed in 0.09s ===================================(venv) C:\Users\057776\PycharmProjects\pytest-demo\testfixture>
可知,session级别的夹具在pytest运行完所有测试用例后销毁。
四、使用夹具(进阶)
1、夹具参数化
params:一个可选的参数列表,默认值为None,可以用来实现 参数化,参数化的时候这里需要用到一个参数request,使用“request.param”来接受请求参数列表,进而实现参数化。
2、夹具中使用其它夹具
pytest 的最大优势之一是其极其灵活的夹具系统。它允许我们将复杂的测试需求归结为更简单和有组织的功能,我们只需要让每个功能描述它们所依赖的东西。
例如下面的例子,新建test_append.py文件,在夹具order中使用了夹具first_entry。
import pytest # Arrange @pytest.fixture def first_entry(): return "a" # Arrange @pytest.fixture def order(first_entry): return [first_entry] def test_string(order): # Act order.append("b") # Assert assert order == ["a", "b"]
3、多个测试函数重复使用一个夹具
夹具可以重复使用,这是pytest功能强大的另外一个原因。不同的测试函数可以请求相同的夹具,并让 pytest 为每个测试提供来自该夹具的自己的结果,这样夹具就可以提供一致的、可重复的结果给不同的测试函数使用。
例如下面的例子,修改test_append.py文件,2个测试函数test_string,test_int都使用了夹具order。
import pytest # Arrange @pytest.fixture def first_entry(): return "a" # Arrange @pytest.fixture def order(first_entry): return [first_entry] def test_string(order): # Act order.append("b") # Assert assert order == ["a", "b"] def test_int(order): # Act order.append(2) # Assert assert order == ["a", 2]
4、测试函数使用多个夹具
测试函数或者夹具中也可以使用多个夹具,例如下面的例子,修改test_append.py文件如下:
import pytest # Arrange @pytest.fixture def first_entry(): return "a" # Arrange @pytest.fixture def second_entry(): return 2 # Arrange @pytest.fixture def order(first_entry, second_entry): return [first_entry, second_entry] # Arrange @pytest.fixture def expected_list(): return ["a", 2, 3.0] def test_string(order, expected_list): # Act order.append(3.0) # Assert assert order == expected_list
5、使用request内置夹具读取上下文信息
request是给请求测试函数提供信息的特殊夹具。请求夹具,来自测试函数或者夹具函数。请求对象允许访问请求测试函数上下文,并且在间接参数化夹具的情况下具有可选的“param”属性。
import pytest
data = [1, 2, 3]
@pytest.fixture(params=data)
def myfixture(request):
return request.param, request.config
def test_one(myfixture):
print(myfixture)
reference:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)