
关于
使用 pytest 最佳实践编写测试,涵盖 fixtures、参数化、mock、异步测试和覆盖率策略。
Python pytest 模式
现代 pytest 模式,用于高效测试。
基本测试结构
import pytest
def test_basic():
"""Simple assertion test."""
assert 1 + 1 == 2
def test_with_description():
"""Descriptive name and docstring."""
result = calculate_total([1, 2, 3])
assert result == 6, "Sum should equal 6"
Fixtures
import pytest
@pytest.fixture
def sample_user():
"""Create test user."""
return {"id": 1, "name": "Test User"}
@pytest.fixture
def db_connection():
"""Fixture with setup and teardown."""
conn = create_connection()
yield conn
conn.close()
def test_user(sample_user):
"""Fixtures injected by name."""
assert sample_user["name"] == "Test User"
Fixture 作用域
@pytest.fixture(scope="function") # 默认 - 每个测试
@pytest.fixture(scope="class") # 每个测试类
@pytest.fixture(scope="module") # 每个测试文件
@pytest.fixture(scope="session") # 整个测试运行
参数化
@pytest.mark.parametrize("input,expected", [
(1, 2),
(2, 4),
(3, 6),
])
def test_double(input, expected):
assert double(input) == expected
# Multiple parameters
@pytest.mark.parametrize("x", [1, 2])
@pytest.mark.parametrize("y", [10, 20])
def test_multiply(x, y): # 4 test combinations
assert x * y > 0
异常测试
def test_raises():
with pytest.raises(ValueError) as exc_info:
raise ValueError("Invalid input")
assert "Invalid" in str(exc_info.value)
def test_raises_match():
with pytest.raises(ValueError, match=r".*[Ii]nvalid.*"):
raise ValueError("Invalid input")
标记
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
pass
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_feature():
pass
@pytest.mark.xfail(reason="Known bug")
def test_buggy():
assert broken_function() == expected
@pytest.mark.slow
def test_performance():
"""Custom marker - register in pytest.ini."""
pass
Mock
from unittest.mock import Mock, patch, MagicMock
def test_with_mock():
mock_api = Mock()
mock_api.get.return_value = {"status": "ok"}
result = mock_api.get("/endpoint")
assert result["status"] == "ok"
@patch("module.external_api")
def test_with_patch(mock_api):
mock_api.return_value = {"data": []}
result = function_using_api()
mock_api.assert_called_once()
pytest-mock(推荐)
def test_with_mocker(mocker):
mock_api = mocker.patch("module.api_call")
mock_api.return_value = {"success": True}
result = process_data()
assert result["success"]
conftest.py
# tests/conftest.py - 共享 fixtures
import pytest
@pytest.fixture(scope="session")
def app():
"""Application fixture available to all tests."""
return create_app(testing=True)
@pytest.fixture
def client(app):
"""Test client fixture."""
return app.test_client()
快速参考
在项目环境中运行 — 前缀 uv run(如 uv run pytest -v)。
| 命令 | 描述 |
|------|------|
| pytest | 运行所有测试 |
| pytest -v | 详细输出 |
| pytest -x | 首次失败时停止 |
| pytest -k "test_name" | 运行匹配的测试 |
| pytest -m slow | 运行标记的测试 |
| pytest --lf | 重新运行上次失败的 |
| pytest --cov=src | 覆盖率报告 |
| pytest -n auto | 并行(pytest-xdist) |
知识参考
pytest 7.0+、Python 3.9+、pytest-asyncio、pytest-mock、pytest-cov、pytest-xdist、conftest、fixtures、参数化、标记
兼容工具
Claude CodeCursorGitHub Copilot
标签
测试

