Pytest框架学习21--fixture总结
@pytest.fixture
是 pytest 测试框架中的一个重要特性,它用于定义测试夹具(fixture),这些夹具可以在测试函数执行前后进行一些准备工作和清理工作。通过使用 @pytest.fixture
装饰器,可以将某些初始化逻辑抽象出来,并且使得这些逻辑能够被多个测试用例共享,从而提高代码的复用性和可维护性。
作用
- 设置测试环境:例如配置数据库连接、初始化外部服务等。
- 准备测试数据:提供测试所需的数据,如用户信息、产品列表等。
- 模拟外部依赖:当测试难以直接访问外部系统时,可以使用 fixture 来模拟这些系统的行为。
- 执行特定操作:在测试前后执行某些特定操作,如临时修改配置、记录日志等。
- 共享资源:在不同的测试用例之间共享资源,减少资源的创建和销毁开销。
定义 Fixture
定义一个 fixture 几乎与定义普通函数相同,主要区别在于需要添加 @pytest.fixture()
装饰器。此外,为了区分测试用例,建议 fixture 的命名不要以 test_
开头
import pytest
@pytest.fixture
def sample_data():
return [1, 2, 3, 4, 5]
参数有scope,params,autouse,ids,name
name为 fixture 指定一个不同于其函数名的名字,可以提高可读性
ids 当使用 params
参数时,可以为每个参数指定一个 ID。这有助于提高输出信息的可读性,尤其是在命令行中查看测试结果时
import pytest
@pytest.fixture(name='custom_name')
def original_name():
return "Custom Fixture Value"
def test_custom_named(custom_name):
print(custom_name)
import pytest
@pytest.fixture(params=[1, 2, 3], ids=['one', 'two', 'three'])
def id_fixture(request):
return request.param
def test_with_ids(id_fixture):
print(f"Testing with id: {id_fixture}")
控制 Scope
可以通过设置 scope
参数来控制 fixture 的生命周期以及它们能被哪些测试用例或测试类访问。默认情况下,scope 是 function
,意味着每次调用测试函数之前都会执行一次 fixture;其他可能的值包括 class
、module
和 session
,分别对应于类级别、模块级别以及整个会话级别的调用
function
:每个测试函数都会调用一次。class
:如果一个测试类中有多个测试用例都调用了 fixture,则该 fixture 只会在第一个测试用例之前调用一次。module
:在整个.py
文件的第一个测试开始前调用,并在所有测试完成后清理。session
:在整个测试会话期间只运行一次,适用于所有测试文件。
返回值
fixture 可以有返回值,如果没有明确指定返回值,默认为 None
。测试用例可以通过参数的形式接收 fixture 的返回值
@pytest.fixture
def login():
print("this is login fixture")
user = "chen"
pwd = 123456
return user, pwd
def test_login(login):
"""将 fixture 修饰的 login 函数作为参数传递给本用例"""
print(login)
assert login[0] == "chen"
assert login[1] == 123456
前置后置处理
pytest 的 fixture 提供了比传统 setup/teardown 更加灵活的方式来实现前置条件(setup)和后置清理(teardown)。这可以通过在 fixture 函数中使用 yield
关键字来完成。yield
之前的代码将在测试函数执行之前运行,而 yield
之后的代码则会在测试函数结束后执行
参数化
对于需要测试不同输入组合的情况,可以利用 params
参数对 fixture 进行参数化。这样做的好处是可以避免编写大量的重复代码,同时还能确保每种情况都被覆盖到
import pytest
@pytest.fixture(params=[1, 2, 3])
def number(request):
return request.param
def test_number(number):
assert number in [1, 2, 3]
自动应用
如果希望某个 fixture 对所有测试用例自动生效,而无需显式地将其作为参数传递,那么可以在定义 fixture 时设置 autouse=True
@pytest.fixture(autouse=True)
def print_hello():
print("Hello, World!")
Fixture 之间的依赖关系
一个 fixture 可以依赖另一个 fixture。这种机制允许我们构建复杂的依赖链,从而更好地组织测试逻辑
import pytest
@pytest.fixture
def db():
return "sqlite:///:memory:"
@pytest.fixture
def session(db):
return create_session(db)
def test_database(session):
assert isinstance(session, Session)