本文目录导读:

Pytest的参数化测试(@pytest.mark.parametrize)非常方便,可以说是pytest最受欢迎的核心功能之一,相比unittest,它能让测试代码量减少50%以上,且可读性更强。
基本使用:一行代码生成多组测试
import pytest
# 最简单的例子:测试平方函数
def square(x):
return x * x
@pytest.mark.parametrize("input, expected", [
(2, 4),
(3, 9),
(0, 0),
(-2, 4),
])
def test_square(input, expected):
assert square(input) == expected
优点:参数组数多时,代码量从N个测试函数减少到1个。
高级特性:组合参数
@pytest.mark.parametrize("username", ["admin", "user", "guest"])
@pytest.mark.parametrize("role", ["viewer", "editor", "admin"])
def test_permission(username, role):
# 自动生成9种组合测试 (3x3)
assert check_permission(username, role)
这比手动写9个测试函数方便太多了。
从外部数据源加载
支持从JSON、YAML、CSV等文件动态生成参数:
import json
def load_test_data():
with open("test_cases.json") as f:
return json.load(f)
@pytest.mark.parametrize("case", load_test_data())
def test_from_file(case):
assert process(case["input"]) == case["expected"]
参数化测试的ID
pytest会自动生成可读的测试ID,失败时一目了然:
test_demo.py::test_square[2-4] PASSED test_demo.py::test_square[3-9] PASSED test_demo.py::test_square[0-0] FAILED test_demo.py::test_square[-2-4] PASSED
你也可以自定义ID:
@pytest.mark.parametrize("input, expected", [
pytest.param(2, 4, id="正数"),
pytest.param(-2, 4, id="负数平方"),
pytest.param(0, 0, id="零"),
])
性能优化:参数化 + fixture
结合fixture可以避免重复初始化:
@pytest.fixture
def database():
db = create_database()
yield db
db.close()
@pytest.mark.parametrize("user_id", [1, 2, 3, 4, 5])
def test_user_balance(database, user_id):
balance = database.query_balance(user_id)
assert balance >= 0
注意:fixture在每个参数组合前执行,适合连接等资源,避免在参数内执行重量级操作。
对比其他框架
| 框架 | 参数化方式 | 代码量 |
|---|---|---|
| unitttest | 继承+手动循环 | 高 |
| pytest | @parametrize装饰器 |
低 |
| nose2 | @parametrize(第三方) |
中 |
注意事项
- 参数多时慎用:1000组以上参数建议分文件或使用
ids参数 - fixture执行次数:fixture在每个参数值都执行,注意资源开销
- 参数顺序:最顶层的
@parametrize是最外层的循环(先变化)
实际项目模板
# 测试API接口
@pytest.mark.parametrize("endpoint, method, status_code", [
("/api/users", "GET", 200),
("/api/users", "POST", 201),
("/api/users/1", "GET", 200),
("/api/users/999", "GET", 404),
], ids=["list", "create", "detail", "not_found"])
def test_crud_endpoints(endpoint, method, status_code):
response = client.request(method, endpoint)
assert response.status_code == status_code
pytest的参数化测试非常方便且功能强大,99%的测试场景下,@pytest.mark.parametrize是最简洁、可维护性最好的方案。