pytest Fixtures 详解:测试夹具的创建、使用与作用域
Introduction
写自动化测试时,经常遇到这样的问题:每个测试都要连接数据库、创建临时文件,但这些准备工作重复写在每个测试函数里会非常冗余。
pytest Fixtures(测试夹具)就是解决这个问题的——你定义一次,pytest 自动在测试前后执行,还能精确控制作用域(function、class、module、session)。
---
基础语法
1. 最简单的 Fixture
import pytest
@pytest.fixture
def sample_data():
return {"name": "pytest", "version": "8.0"}
作为参数传入测试函数即可使用:
def test_data_access(sample_data):
assert sample_data["name"] == "pytest"
assert sample_data["version"] == "8.0"
2. Setup 和 Teardown
用 yield 实现「测试前准备 + 测试后清理」:
import pytest
import os
@pytest.fixture
def temp_dir():
"""创建临时目录,测试后清理"""
path = "/tmp/pytest_test_dir"
os.makedirs(path, exist_ok=True)
yield path # 测试在此处执行
# teardown:测试结束后执行
import shutil
if os.path.exists(path):
shutil.rmtree(path)
def test_create_file(temp_dir):
filepath = os.path.join(temp_dir, "test.txt")
with open(filepath, "w") as f:
f.write("hello")
assert os.path.exists(filepath)
assert os.path.getsize(filepath) == 5
3. Fixture 作用域(Scope)
| scope | 说明 | 何时创建 | 何时销毁 |
|-------|------|----------|----------|
| function(默认) | 每个测试函数执行一次 | 第一次使用时 | 测试结束后 |
| class | 每个测试类执行一次 | 第一次使用时 | 类最后一个测试结束后 |
| module | 每个 .py 文件执行一次 | 文件首次使用时 | 模块所有测试结束后 |
| session | 整个测试会话执行一次 | 会话开始时 | 会话结束时 |
@pytest.fixture(scope="module")
def db_connection():
"""整个模块只建立一次数据库连接"""
conn = create_db_connection()
yield conn
conn.close()
class TestUserAPI:
def test_get_user(self, db_connection):
...
def test_create_user(self, db_connection):
...
4. autouse:自动调用
不需要显式传入,某些 fixture 可以设置为自动执行:
@pytest.fixture(autouse=True)
def test_env_setup():
"""每个测试函数自动执行,不需要手动传入"""
os.environ["TESTING"] = "1"
yield
os.environ.pop("TESTING", None)
5. Fixture 互相依赖
Fixture 之间可以相互引用:
@pytest.fixture
def database():
return DatabaseConnection()
@pytest.fixture
def user_repo(database):
return UserRepository(database)
def test_create_user(user_repo):
user = user_repo.create(name="pytest")
assert user.name == "pytest"
---
运行效果
pytest test_fixtures.py -v
# output:
# test_fixtures.py::test_create_file PASSED [50%]
# test_fixtures.py::test_data_access PASSED [50%]
---
常见问题
Q1: fixture 和 setup/teardown 有什么区别?
@pytest.fixture + yield = setup + teardown,能返回值给测试函数;setup/teardown 是类/函数级别的钩子,不能返回值。
Q2: fixture 报 "fixture not found"?
检查是否: 1. fixture 和测试函数在同一个文件 2. fixture 写在 conftest.py 中(推荐,模块间共享) 3. 参数名称与 fixture 名称完全一致Q3: conftest.py 怎么用?
放在测试目录根部,所有子目录的测试都能自动使用其中的 fixtures:tests/
├── conftest.py ← fixtures 放这里
├── test_api.py
└── test_unit/
└── test_sample.py
---
延伸阅读
- [[pytest 参数化测试]] — 多组数据驱动
- [[pytest 插件生态]] — pytest-cov、pytest-html、pytest-xdist
- [[Selenium + pytest 集成]] — Web UI 测试实战
---
有问题欢迎在评论区交流!