跳过 TDD
错误:先写代码后写测试 正确:遵循 RED-GREEN-REFACTOR 循环
来源: everything-claude-code 技能库
python-testing 是使用 pytest 进行 Python 应用全面测试的技能。它涵盖 TDD 方法论、最佳实践、Fixtures、Mocking、参数化和覆盖率要求。
始终遵循 TDD 循环:
graph TD A[RED: 写失败的测试] --> B[GREEN: 写最小代码] B --> C[REFACTOR: 重构优化] C --> A
# 步骤 1: 编写失败的测试 (RED)def test_add_numbers(): result = add(2, 3) assert result == 5
# 步骤 2: 编写最小实现 (GREEN)def add(a, b): return a + b
# 步骤 3: 重构 (REFACTOR)| 目标 | 说明 |
|---|---|
| 目标 | 80%+ 代码覆盖率 |
| 关键路径 | 必须 100% 覆盖 |
| 工具 | pytest —cov |
pytest --cov=mypackage --cov-report=term-missing --cov-report=htmlimport pytest
def test_addition(): """测试基本加法。""" assert 2 + 2 == 4
def test_string_uppercase(): """测试字符串大写。""" text = "hello" assert text.upper() == "HELLO"
def test_list_append(): """测试列表追加。""" items = [1, 2, 3] items.append(4) assert 4 in items assert len(items) == 4# 相等断言assert result == expected
# 不相等断言assert result != unexpected
# 真值断言assert result is Trueassert result is None
# 浮点数断言assert abs(result - expected) < 0.0001
# 异常断言with pytest.raises(ValueError): function()
# 近似断言assert math.isclose(result, expected, rel_tol=1e-9)Fixtures 是 pytest 最强大的功能之一,用于提供测试数据和 setup/teardown 逻辑。
import pytest
@pytest.fixturedef user(): """创建测试用户。""" return {"name": "test", "email": "test@example.com"}
def test_user_name(user): assert user["name"] == "test"| 作用域 | 说明 | 示例 |
|---|---|---|
| function | 每个测试函数执行一次 | 默认 |
| class | 每个测试类执行一次 | @pytest.fixture(scope=“class”) |
| module | 每个模块执行一次 | @pytest.fixture(scope=“module”) |
| session | 整个测试会话执行一次 | @pytest.fixture(scope=“session”) |
@pytest.fixturedef db_connection(): """数据库连接 fixture。""" return create_connection()
@pytest.fixturedef user_repository(db_connection): """依赖数据库连接的 repository。""" return UserRepository(db_connection)@pytest.fixturedef user_factory(): """用户工厂 fixture。""" def _create_user(name): return {"name": name, "id": generate_id()} return _create_user
def test_create_user(user_factory): user = user_factory("张三") assert user["name"] == "张三"使用 unittest.mock 或 pytest-mock 进行模拟。
from unittest.mock import Mock, patch
def test_api_call(): mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": "test"}
with patch('requests.get', return_value=mock_response): result = api.get_data() assert result == {"data": "test"}# 模拟整个模块@patch('module.function')def test_function(mock_func): mock_func.return_value = 42 assert module.function() == 42
# 模拟上下文管理器@patch('builtins.open', create=True)def test_file_read(mock_open): mock_open.return_value.__enter__.return_value.read.return_value = "file content" # 测试代码Spy 允许你监视函数的调用,但不替换实现:
def test_spy_example(records): spy = pytest.spy(records, 'save') records.save() spy.assert_called_once()参数化允许用不同输入运行同一测试:
@pytest.mark.parametrize("input,expected", [ (2, 4), (3, 9), (4, 16), (5, 25),])def test_square(input, expected): assert input ** 2 == expected
@pytest.mark.parametrize("a,b,expected", [ (1, 2, 3), (0, 0, 0), (-1, 1, 0), (100, 200, 300),])def test_add(a, b, expected): assert a + b == expected@pytest.mark.parametrize("a", [1, 2, 3])@pytest.mark.parametrize("b", [10, 20])def test_combinations(a, b): # 将运行 3 * 2 = 6 次 assert isinstance(a + b, int)✅ 正确做法:1. 先写一个失败的测试 (RED)2. 写最少的代码让测试通过 (GREEN)3. 重构代码确保测试仍然通过 (REFACTOR)4. 提交测试和代码
❌ 错误做法:1. 先写代码,然后写测试2. 测试覆盖率低就提交3. 不运行完整的测试套件✅ 正确做法:1. 识别外部依赖(API、数据库、文件系统)2. 使用 @patch 或 Mock 替换3. 验证调用参数和次数4. 测试边界条件和异常
❌ 错误做法:1. 依赖真实的外部服务2. Mock 整个类而不是具体方法3. 不验证 mock 的调用✅ 正确做法:1. Fixture 应该是纯函数,无副作用2. 使用合适的 scope 减少重复创建3. 清晰的 fixture 命名4. 依赖关系显式声明
❌ 错误做法:1. Fixture 中包含测试逻辑2. Fixture 之间有隐藏的依赖3. Scope 设置过大导致测试污染# 运行所有测试pytest
# 运行特定文件pytest tests/test_api.py
# 运行特定测试pytest tests/test_api.py::test_get_user
# 显示详细输出pytest -v
# 停在第一个失败pytest -x
# 显示局部变量pytest -l
# 生成覆盖率报告pytest --cov=mypackage --cov-report=term-missing
# 运行上次失败的测试pytest --lf
# 并行执行pytest -n auto
# 只运行失败的测试pytest --failed-first跳过 TDD
错误:先写代码后写测试 正确:遵循 RED-GREEN-REFACTOR 循环
Mock 过度
错误:Mock 太多实现细节 正确:只 Mock 外部依赖
Fixture 滥用
错误:Fixture 中包含复杂逻辑 正确:保持 Fixture 简单纯净
忽略覆盖率
错误:覆盖率低就提交 正确:80%+ 覆盖率,关键路径 100%
何时使用
何时不用
关键要点
常见错误
Python 测试技能强调:
| 特性 | pytest | unittest |
|---|---|---|
| 语法 | 函数式 | 类式 |
| Fixture | 原生支持 | 需继承 |
| 参数化 | 原生支持 | 需插件 |
| Mock | 需安装 | 原生支持 |
| 社区 | 活跃 | 标准库 |
test_*.py 或 *_test.pytest_*Test*| 技能 | 关系 |
|---|---|
| tdd-workflow | TDD 工作流基础 |
| python-patterns | Python 编程模式 |
| code-review | 代码审查 |
pip install pytest pytest-cov pytest-mocktest_*.pypytestpytest --cov官方原文: python-testing SKILL.md
💡 提示:测试是最好的文档,好的测试能让代码自己说话。