pytest fixture
pytest fixture
1. 通过conftest.py 共享fixture
@pytest.fixture()装饰器用于声明函数是一个fixture,如果测试用例的参数列表中包含fixture, pytest会优先搜索该测试用例所在的模块,然后搜索conftest.py文件。
conftest.py中的fixture可以供其所在目录及其子目录下的测试案例使用,并且conftest.py 文件不能被导入
2. 使用fixture执行配置及销毁逻辑
import pytest
@pytest.fixture(scope='module')
def get_data():
print('fixture start')
yield 44
print('fixture end')
def test_add(get_data):
print(123)
print(get_data)
def test_add2(get_data):
print(1234)
print(get_data)
def test_add3(get_data):
print(456)
print(get_data)
fixture 函数会在测试函数之前运行,但如果fixture函数包含yield,那么系统会在yield处停止,转而运行测试函数,等测试函数执行完毕后再回到fixture,继续执行yield后面的代码。因此可以将yield 之前的代码视为配置(setup)的过程,将yield之后的代码视为清理(teardown)的过程,无论测试过程中发生了什么,yield之后的代码都会被执行。所以yield 可以用作测试案例的前置条件。
I:\APIAutoTest>pytest -v --setup-show test.py
================================================================================================================================================== test session starts ===================================================================================================================================================
platform win32 -- Python 3.9.5, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:~\python39\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.9.5', 'Platform': 'Windows-10-10.0.19042-SP0', 'Packages': {'pytest': '6.2.4', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.9.43', 'html': '3.1.1', 'metadata': '1.11.0'}}
rootdir: I:\APIAutoTest
plugins: allure-pytest-2.9.43, html-3.1.1, metadata-1.11.0
collected 3 items
test11.py::test_add
SETUP M get_data
test11.py::test_add (fixtures used: get_data)PASSED。
test11.py::test_add2
test11.py::test_add2 (fixtures used: get_data)PASSED
test11.py::test_add3
test11.py::test_add3 (fixtures used: get_data)PASSED
TEARDOWN M get_data
运行结果如上,
pytest 提供命令--setup-show
可以看到测试过程中执行的顺序是什么,以及执行的先后顺序, setup后面的M表示的事fixture的作用范围
3. 使用fixture传递测试数据
fixture非常适合存放测试数据,并且它可以返回任何测试数据.
如果测试结果为Fail,用户就知道失败是发生在核心测试函数内,测试结果是Error,就知道失败是发生在测试依赖的Fixture。
如下:
import pytest
#异常发生在测试函数内,测试结果为Fail
@pytest.fixture(scope='module')
def get_data():
print('fixture start')
yield 44
print('fixture end')
def test_add(get_data):
get_data + 'a'
print(get_data)
================================================== FAILURES===============================================
_______________________________________________ test_add__________________________________________________
get_data = 44
def test_add(get_data):
> get_data + 'a'
E TypeError: unsupported operand type(s) for +: 'int' and 'str'
import pytest
# 异常发生在fixture内,测试结果为Error
@pytest.fixture(scope='module')
def get_data():
print('fixture start')
yield 44 + 'a'
print('fixture end')
def test_add(get_data):
print(get_data)
================================== ERRORS ========================================
_______________________ ERROR at setup of test_add _______________________________
@pytest.fixture(scope='module')
def get_data():
print('fixture start')
> yield 44 + 'a'
E TypeError: unsupported operand type(s) for +: 'int' and 'str'
4. 指定fixture的作用范围
测试函数中可以使用多个fixture。
test_1:
/__init__.py
/contfest.py
/test_1.py
/test2:
/conftest.py
/test_2.py
如果test_1文件夹下的conftest.py和test_2文件夹下的conftest.py中都有fixture,那test_2.py中都可以使用这二个文件夹中的fixture
@pytest.fixture的scope参数有四个待选值,分别是function,class,module,package,session
-
function: the default scope, the fixture is destroyed at the end of the test.
-
class: the fixture is destroyed during teardown of the last test in the class.
-
module: the fixture is destroyed during teardown of the last test in the module.
-
package: the fixture is destroyed during teardown of the last test in the package.
-
session: the fixture is destroyed at the end of the test session.
function级别的fixture,每个测试函数都会运行fixture(都会setup和teardown)function是scope的默认值
class级别的fixture,每个测试类运行一次fixture,,无论测试类里面有多少个类方法,都可以共享这个fixture,运行完类的所有测试函数后会销毁fixture。 比如一个py文件里面与三个类,fixture的级别是class,那会调用三次fixture
module级别的fixture,运行完一个py文件后,销毁fixture,也就是说运行一个py文件,运行一次fixture。
package 级别的fixture,运行完文件下的所有测试的py文件之后,销毁fixture,
session级别的fixture,测试完成后才会销毁fixture
fixture只能使用同级别的fixture,或者比自己更高级别的fixture,比如函数级别的fixture可以使用函数级别的fixture,也可以使用module级别的fixture。
在定义fixture的时候,将参数autouse设置为True时,则在执行用例的时候自动去加载,无需显示调用
5. fixture的重命名
import sys
import pytest
@pytest.fixture(scope='class', name='test')
def test_fixture_test_20210109():
print('fixture start')
yield 44
print('fixture end')
class TestA:
def test_a1(self, test):
print('{} call'.format(sys._getframe().f_code.co_name))
6. fixture的参数化
fixture 参数化和参数化测试相比,对测试函数的参数可以pre-excute
import pytest
def id_func(b):
return 'id is {}'.format(b)
num = [4, 2, 3]
@pytest.fixture(params=num, ids=id_func, scope='function')
def get_num(request):
print('get num {}'.format(request.param))
request.param += 1 # 对即将要传入测试函数的参数进行统一的pre-excute
return request.param
# ids参数可以指定为一个函数,供测试函数生成标识
def test_1(get_num):
print(get_num)
def test_2(get_num):
print(get_num)
userkeylist = [4, 2, 3]
@pytest.mark.parametrize('userkey', userkeylist)
def test_user(userkey):
# 在测试函数中,对参数进行操作
userkey += 1
print(userkey)
运行结果如下:
============================= test session starts =============================
collecting ... collected 8 items
test_A2.py::test_1[id is 4] get num 4
PASSED [ 12%]5
test_A2.py::test_1[id is 2] get num 2
PASSED [ 25%]3
test_A2.py::test_1[id is 3] get num 3
PASSED [ 37%]4
test_A2.py::test_2[id is 4] get num 4
PASSED [ 50%]5
test_A2.py::test_2[id is 2] get num 2
PASSED [ 62%]3
test_A2.py::test_2[id is 3] get num 3
PASSED [ 75%]4
test_A2.py::test_user[4] PASSED [ 33%]5
test_A2.py::test_user[2] PASSED [ 66%]3
test_A2.py::test_user[3] PASSED [100%]4
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)