工程化
测试体系深度
pytest、Mock、测试覆盖率、属性测试和测试金字塔
- 掌握 pytest 的 fixture/parametrize/mark
- 理解 Mock 的正确用法和反模式
- 掌握测试覆盖率
- 了解属性测试(hypothesis)和测试金字塔
测试体系深度
没有测试的代码是遗留代码。工业级项目的测试不是随便写几个 assert,而是一套完整的质量保障体系。
pytest 核心
Python
# pytest 基础
# 文件:test_*.py 或 *_test.py
# 函数:test_*
import pytest
# 1. 基本断言(pytest 重写 assert,提供详细输出)
def test_add():
assert 1 + 1 == 2
assert "hello".upper() == "HELLO"
assert [1, 2, 3] == [1, 2, 3]
# 2. 参数化测试
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300),
])
def test_add_param(a, b, expected):
assert a + b == expected
# 3. fixture(测试的依赖注入)
@pytest.fixture
def sample_list():
return [1, 2, 3]
def test_list(sample_list):
assert len(sample_list) == 3
# 4. fixture 作用域
@pytest.fixture(scope="module") # function/class/module/session
def db_connection():
conn = create_connection()
yield conn # yield 之前是 setup,之后是 teardown
conn.close()
# 上面是标准 pytest 测试文件的写法:在专业开发环境里用 pytest 命令自动发现并运行;
# App 内置的是教学运行环境(未捆绑 pytest 命令行),所以这一块只作语法展示,
# 紧接着下面用不依赖任何第三方库的纯 Python,帮你亲手体会「参数化」和「fixture」到底在做什么。示例代码(可运行)
Python 0%
unittest.mock — Mock 的正确用法
示例代码(可运行)
Python 0%
🐍资深工程师经验谈
Mock 的黄金法则:mock 外部边界,不 mock 内部逻辑。好的测试应该是:Arrange→Act→Assert。一个测试只测一个行为。测试名应该是句子:test_转账时余额不足应该抛出异常。如果测试需要 10 个 mock,说明你的代码耦合太高了——该重构了。
测试覆盖率
Python
# coverage.py / pytest-cov
# pip install pytest-cov
# pytest --cov=mypackage --cov-report=html
# pytest --cov=mypackage --cov-report=term-missing
# 配置在 pyproject.toml [tool.coverage]
# branch = true, fail_under = 80
# 覆盖率目标:核心逻辑90%+, 整体80%+
print("覆盖率不是目的,测试质量才是")测试金字塔
Python
# 测试金字塔
# 顶层: E2E(少量,慢,真实环境)
# 中层: 集成测试(适量,验证模块协作)
# 底层: 单元测试(大量,快,隔离)
# 反模式: 冰淇淋(太多E2E,太慢不稳定)
# 正确: 大量单元测试 + 适量集成测试 + 少量E2E
print("单元测试 > 集成测试 > E2E测试")
# 测试类型:
# - 单元测试:隔离测试单个函数/类,mock外部依赖,毫秒级
# - 集成测试:测试多个模块协作,用真实数据库(测试容器)
# - E2E测试:从用户视角测试完整流程,浏览器/API
# - 契约测试:验证服务间API契约(pact)
# - 性能测试:pytest-benchmark / locust
# - 突变测试:mutmut(验证测试能否捕获代码变异)选学
属性测试 (Property-Based Testing)
普通测试要写具体的输入和期望输出。属性测试描述「性质」,让框架自动生成大量测试用例。
Python
# pip install hypothesis
from hypothesis import given, strategies as st
# 性质:排序后再排序结果不变
def test_sort_idempotent():
# 但用 hypothesis 自动生成各种列表
pass
# @given(st.lists(st.integers()))
# def test_sort_twice(lst):
# assert sorted(sorted(lst)) == sorted(lst)
# @given(st.text())
# def test_reverse_reverse(s):
# assert s[::-1][::-1] == s
# hypothesis 会自动生成边界情况:
# 空列表、超长列表、负数、Unicode、NaN...
# 找到失败用例后自动缩小到最小反例选择题
fixture 的 scope='module' 意味着什么?
选择题
Mock 的黄金法则是?
资深工程师加餐
底层原理 · 大厂视角 · 工程经验,点卡片展开
底层是大量、快速、稳定的单元测试(优先覆盖纯函数与边界/异常路径),中间是少量集成测试(验证模块协作),顶端是少量端到端测试(慢且脆)。测试最大的价值是当「安全网」:有它你才敢放心重构。没测试兜底的重构,本质是在赌博。写用例先想正常、边界、异常三类。
挑战任务
pytest 挑战
简单+50 XP
就用 pytest 风格写参数化测试,测字符串反转函数。
pytest 挑战
Python 0%
2 个测试用例
课后作业
计算器测试
中等+20 XP
给 divide 函数写完整 pytest 测试用例,用 parametrize 覆盖正常、边界和异常情况。
计算器测试
Python 0%
1 个测试用例