Pytest 中的 Fixture
Pytest 是 Python 中的一个单元测试框架,而 Fixture 是为 Pytest 测试提供其运行所需的数据、对象、环境和状态的函数。它负责“准备工作”(Setup)和“清理工作”(Teardown)。
Pytest Fixture 的基础用法
什么是 Fixture:在 Pytest 中,一个 Fixture 就是一个被 @pytest.fixture
装饰器标记的 Python 函数。这个函数的名字可以被其他测试函数当作参数来使用。当 Pytest 发现一个测试函数请求了一个 Fixture,它会:
- 在运行该测试函数之前,先去执行对应的 Fixture 函数。
- 将 Fixture 函数的返回值(如果有的话)传递给测试函数。
- 在测试函数执行完毕后,执行 Fixture 中定义的清理操作。
@pytest.fixture 的用法:假设我们有好几个测试用例,都需要用到一个相同的数据字典。
- 没有 Fixture 的写法(不推荐):
user_data
这个字典在每个测试中都重复定义了,非常冗余。
# test_without_fixture.py
=
# ... 测试显示逻辑 ...
assert ==
=
# ... 测试权限逻辑 ...
assert ==
- 使用 Fixture 的写法(推荐):Pytest 在执行
test_user_info_display
和test_user_permission
时,会自动找到并执行user_data
Fixture,然后将它的返回值data
注入到测试函数的user_data
参数中。
# test_with_fixture.py
# 1. 使用 @pytest.fixture 装饰器来定义一个 Fixture
"""这是一个提供用户数据的 Fixture"""
=
return
# 2. 测试函数直接把 Fixture 函数名作为参数
"""测试用户信息显示"""
assert ==
"""测试用户权限"""
assert ==
使用 yield 实现 Setup 和 Teardown:如果我们需要清理工作(Teardown),我们可以使用 yield
关键字,其之前的代码是 Setup 部分,其之后的代码是 Teardown 部分。
# test_with_teardown.py
"""创建一个临时文件,测试后删除"""
# --- Setup: yield 之前的部分 ---
=
# 使用 yield 将文件路径提供给测试函数
yield
# --- Teardown: yield 之后的部分 ---
"""测试读取临时文件的内容"""
=
assert ==
"""测试文件是否存在"""
assert
Fixture 进阶用法
Fixture 的 Scope:默认情况下,Fixture 的作用域是 function
,意味着它会对每一个使用它的测试函数都执行一次,有时候这会造成不必要的开销。我们可以通过 scope
参数来控制 Fixture 的生命周期:
scope="function"
(默认): 每个测试函数执行一次。scope="class"
: 每个测试类(Test Class)只执行一次。scope="module"
: 每个模块(.py
文件)只执行一次。scope="session"
: 整个测试会话(运行pytest
命令一次)只执行一次。
例如连接数据库是一个耗时操作,我们希望整个测试文件(模块)只连接一次:
# test_db_connection.py
# 使用 scope="module"
"""一个昂贵的数据库连接,整个模块共享"""
# 模拟一个连接对象
=
yield
=
assert ==
assert ==
Fixture 之间相互依赖:一个 Fixture 可以像测试函数一样,请求另一个 Fixture
# test_fixture_dependency.py
"""启动一个 API 服务器,整个会话只启动一次"""
=
yield
# <--- 这里依赖了 api_server Fixture
"""创建一个 API 客户端,连接到服务器"""
=
return
"""测试登录接口"""
assert ==