Pytest入门系列之pytest的fixture
pytest 是 Python 最流行的测试框架之一,而 fixture 是 pytest 提供的 强大测试前后置机制,用于管理测试依赖、初始化测试环境和清理资源。
什么是 fixture?
在 pytest 中,fixture 是一种特殊的函数,用于 在测试开始前进行准备工作,并在测试结束后进行清理。
它可以用于:
✅ 创建测试数据
✅ 数据库连接
✅ 初始化 WebDriver(Selenium)
✅ 文件操作
✅ 清理资源
📌 基本语法
1 2 3 4 5 6 7 8 9
| import pytest
@pytest.fixture def sample_data(): return {"name": "Alice", "age": 25}
def test_sample(sample_data): assert sample_data["name"] == "Alice"
|
🔍 解析:
@pytest.fixture 让 sample_data() 成为一个 fixture。
test_sample() 通过参数 自动接收 sample_data() 的返回值。
运行时 pytest 自动调用 fixture,无需手动传参。
fixture 的作用域 (scope)
fixture 默认 作用于每个测试函数(function 级别),但 pytest 允许我们通过 scope 控制
1 2 3 4
| @pytest.fixture(scope="function") @pytest.fixture(scope="class") @pytest.fixture(scope="module") @pytest.fixture(scope="session")
|
📌 示例:不同作用域的 fixture
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import pytest
@pytest.fixture(scope="session") def db_connection(): print("\n🔗 连接数据库") yield print("\n❌ 关闭数据库")
@pytest.fixture(scope="function") def test_user(): print("\n👤 创建测试用户") yield {"username": "test_user"} print("\n🗑️ 删除测试用户")
def test_example_1(db_connection, test_user): print("✅ 运行 test_example_1")
def test_example_2(db_connection, test_user): print("✅ 运行 test_example_2")
|
🔍 解析:
db_connection() scope=”session” → 整个测试运行一次。
test_user() scope=”function” → 每个测试函数运行一次。
🔄 运行顺序
1
| pytest test_example.py -s
|
1 2 3 4 5 6 7 8 9 10
| 🔗 连接数据库 👤 创建测试用户 ✅ 运行 test_example_1 🗑️ 删除测试用户
👤 创建测试用户 ✅ 运行 test_example_2 🗑️ 删除测试用户 ❌ 关闭数据库
|
yield 语句管理 fixture
fixture 不仅可以提供数据,还可以执行“前后置”逻辑,yield 允许在 测试结束后执行清理工作。
📌 示例:使用 yield 进行资源清理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import pytest
@pytest.fixture def open_file(): file = open("test_file.txt", "w") print("\n📂 打开文件") yield file print("\n❌ 关闭文件") file.close()
def test_write_file(open_file): open_file.write("Hello, pytest fixture!") assert open_file.closed is False
def test_file_closed(open_file): assert open_file.closed is False
|
🔍 运行流程
测试开始前:执行 print(“\n📂 打开文件”) 并打开文件。
测试运行中:yield 让测试函数使用 file。
测试结束后:执行 file.close() 关闭文件。
autouse=True 自动应用 fixture
📌 如果不想手动传入 fixture,可以使用 autouse=True 自动应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import pytest
@pytest.fixture(autouse=True) def setup_teardown(): print("\n🔧 测试前置操作") yield print("\n🗑️ 测试后置清理")
def test_case_1(): print("✅ 运行 test_case_1")
def test_case_2(): print("✅ 运行 test_case_2")
|
🔍 运行输出
1 2 3 4 5 6 7
| 🔧 测试前置操作 ✅ 运行 test_case_1 🗑️ 测试后置清理
🔧 测试前置操作 ✅ 运行 test_case_2 🗑️ 测试后置清理
|
📌 适用于
日志记录
数据库连接
全局资源初始化
conftest.py 让 fixture 适用于所有测试
如果 fixture 在多个测试文件中通用,可以放入 conftest.py,这样所有测试都会自动找到它。
📌 conftest.py
1 2 3 4 5 6
| import pytest
@pytest.fixture def global_data(): return {"project": "pytest"}
|
📌 在 test_sample.py 里直接使用
1 2 3
| def test_global(global_data): assert global_data["project"] == "pytest"
|
📌 这样可以在任何测试文件里使用 global_data,无需 import。
fixture 之间的依赖
fixture 可以互相依赖:
1 2 3 4 5 6 7 8 9 10 11 12
| @pytest.fixture def user_data(): return {"username": "alice"}
@pytest.fixture def authenticated_user(user_data): user_data["authenticated"] = True return user_data
def test_auth_user(authenticated_user): assert authenticated_user["authenticated"] is True
|
📌 运行时 authenticated_user 会先调用 user_data,实现依赖注入。
参数化 fixture
📌 有时,我们需要对 fixture 传递多个值,可以用 params 参数
1 2 3 4 5 6 7
| @pytest.fixture(params=["admin", "editor", "viewer"]) def user_role(request): return request.param
def test_user_role(user_role): assert user_role in ["admin", "editor", "viewer"]
|
📌 运行时,pytest 会 自动为 user_role 生成 3 组测试:
1 2 3
| test_user_role[admin] ✅ test_user_role[editor] ✅ test_user_role[viewer] ✅
|
组合多个 fixture
1 2 3 4
| def test_multiple_fixture(user_data, authenticated_user): assert authenticated_user["username"] == "alice" assert authenticated_user["authenticated"] is True
|
📌 pytest 会自动解析依赖,先执行 user_data,再执行 authenticated_user。
总结
功能 |
关键特性 |
fixture 基础 |
@pytest.fixture 定义 |
作用域 (scope) |
"function", "class", "module", "session" |
pytest test_sample.py::test_func |
运行指定测试函数 |
yield 清理资源 |
yield 之后执行清理 |
自动应用 |
autouse=True |
conftest.py |
共享 fixture |
参数化 fixture |
params=[...] |