单元测试的局限性 | AI生成和翻译
诚实地说:这是一种普遍看法,但实际上它只说对了一半。
单元测试擅长于:
- 纯逻辑、算法、数据转换
- 业务规则中的边界情况
- 开发过程中的快速反馈循环
- 测试那些在真实系统中难以触发的错误路径
但单元测试有一个根本问题:模拟(mock)会撒谎。
当你模拟数据库、HTTP 客户端或文件系统时,你测试的是你对这些依赖的假设——而不是实际行为。你可以拥有 100% 的单元测试覆盖率,而系统在生产中完全崩溃,原因如下:
# 这个单元测试轻松通过
def test_parse_user():
mock_db = Mock()
mock_db.query.return_value = {"name": "Alice"}
result = get_user(mock_db, 1)
assert result.name == "Alice" # ✓
# 但在生产中,实际的查询返回
# {"name": "Alice", "role": null} 然后系统炸裂
真实的层级关系是:
单元测试: 快速、廉价、测试逻辑分支
盲区:集成、真实 I/O、序列化
集成测试: 测试真实组件协同工作
捕获:实际数据库查询、HTTP 行为、序列化
对关键路径来说值得付出成本
端到端/API 测试:测试完整的用户旅程
捕获:任何数量的模拟都无法揭示的问题
务实的做法是:
- 纯逻辑 → 单元测试(无需模拟,仅需输入/输出)
- I/O 密集代码 → 集成测试(真实数据库、真实 HTTP,仅隔离环境)
- 关键路径 → 两者都做
“模拟一切”的学派会导致测试自信地通过,而系统却在燃烧。真正的技巧在于知道何时使用模拟能增加信心,何时会掩盖风险。
单元测试更擅长的是:速度、简单性、隔离性。它们更不擅长的是:证明系统确实能正常工作。