pytest 是 Python 最流行的测试框架,相比 unittest 不需要继承类、不需要 assertXxx API,普通函数 + 原生 assert 即可写测试。掌握命名规则、断言、参数化、Fixture 即可覆盖 80% 场景。

安装与命名约定

pip install -U pytest
pytest --version

pytest 通过文件名/函数名自动发现测试:

类型命名规则
测试文件test_*.py*_test.py
测试函数test_ 开头
测试类Test 开头,无 __init__

第一个测试

# test_calculator.py
def add(a, b):
    return a + b
 
def test_add():
    assert add(1, 2) == 3
    assert add(-1, 1) == 0
 
# 运行
# pytest        # 全部
# pytest -v     # 详细

断言

直接用 Python assert,失败时 pytest 会自动展示双方差异:

assert add(2, 3) == 5
assert "python" in "pytest"
assert 0.1 + 0.2 == pytest.approx(0.3)         # 浮点比较
 
with pytest.raises(ZeroDivisionError):          # 异常断言
    1 / 0

参数化

@pytest.mark.parametrize 一次声明多组输入:

@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (-1, 1, 0),
    (0.1, 0.2, 0.3),
])
def test_add(a, b, expected):
    assert add(a, b) == pytest.approx(expected)

Fixture:前置/后置 + 复用

@pytest.fixture
def sample_data():
    data = [1, 2, 3, 4]
    yield data
    data.clear()  # yield 之后是 teardown
 
def test_len(sample_data):
    assert len(sample_data) == 4
 
def test_sum(sample_data):
    assert sum(sample_data) == 10

可控制作用域:scope="function|class|module|session"。放到 conftest.py 即对整个目录生效。

常用命令

命令作用
pytest全部测试
pytest -v详细输出
pytest path/test.py指定文件
pytest path/test.py::test_func指定函数
pytest -x首次失败即停
pytest --lf只跑上次失败的
pytest -k "expr"按表达式选择测试名
pytest --html=report.htmlHTML 报告(需 pytest-html

常见问题

问题解决
测试未被发现检查命名规则与 pytest.ini / pyproject.toml 中的 testpaths
浮点断言失败使用 pytest.approx()
Fixture 未注入检查参数名是否与 fixture 名一致;fixture 是否在 conftest.py 中可被发现
想看完整 print-s 关闭 capture