单元测试应验证单个函数或方法在隔离环境下的行为,需mock外部依赖;避免测流程、UI或真实I/O;命名用test_[功能]_[场景]_[预期];优先pytest+原生assert;断言要具体到关键字段。

单元测试该测什么,不该测什么
单元测试的核心是验证单个函数或方法在隔离环境下的行为是否符合预期,不是用来测整个流程、外部依赖或 UI 交互的。如果一个函数调用了 requests.get、读了文件、连了数据库,那就先得用 mock 或 patch 把这些依赖掐掉。
常见误操作包括:
- 在测试里写
assert response.status_code == 200—— 这属于集成测试范畴,除非你明确在测 HTTP 客户端封装层 - 测试中创建真实数据库连接并执行
INSERT—— 应该用内存 SQLite 或unittest.mock替换 ORM 的save()方法 - 给一个纯计算函数(比如
calculate_tax(amount, rate))写一堆边界 case 却漏掉amount=0或负数 —— 数值类函数必须覆盖零值、负值、极大值、None和类型错误
如何组织 test_*.py 文件和测试方法名
Python 的 unittest 和 pytest 都默认识别以 test_ 开头的文件和方法。命名不是随便加前缀,而是要能一眼看出“被测对象 + 场景 + 期望结果”。
推荐格式:test_[function_name]_[scenario]_[expected_behavior],例如:
立即学习“Python免费学习笔记(深入)”;
test_calculate_tax_with_zero_amount_returns_zero
test_parse_json_invalid_input_raises_ValueError
test_user_login_success_returns_token
这样在 CI 失败时,光看测试名就能定位问题模块和触发条件,不用点开代码。避免使用 test_case1、test_main 这类无法传达语义的名字。
setup/teardown 是不是每次都要写
不是。只有当多个测试方法共享相同初始化逻辑(比如创建临时目录、预置测试数据)且成本较高时,才考虑用 setUp() / tearDown()(unittest)或 @pytest.fixture(pytest)。否则,宁可每个测试里单独构造输入数据。
和网商城,手机平台(WAP2.0界面)v1.0测试版(带全站测试数据+图片)。 特色功能: 商品基本信息中编号条型码生成设计中,选择商品类型。 商品价格,支持单一价格,同时支持开启规格,可以分别设置价格。 商品属性,支持自定属性,不同的商品类型加载不同的商品属性,支持按属性检索浏览。 扩展属性:支持添加文字属性,图文属性等,具体功能请试用 赠送礼品:添加购买赠送的礼品(礼品后台管理)。 相关专题
原因很实际:
- 共享状态容易引发测试间污染 —— 某个测试改了全局变量或缓存,下一个测试就莫名其妙失败
- 调试困难 —— 错误堆栈里看不出是 setup 还是测试体本身出的问题
-
setUp()里抛异常会导致整组测试跳过,掩盖真正要测的分支逻辑
简单场景下,直接在测试方法开头写 data = {"name": "test", "age": 25} 更清晰、更可控。
断言该用 assert 还是 self.assertEqual
用 assert 语句就行,但前提是用 pytest。它会自动重写 assert 表达式,提供清晰的失败信息(比如告诉你 a=3 而不是只报 AssertionError)。而 unittest.TestCase 的 self.assertEqual(a, b) 在老项目里仍常见,但它对复杂嵌套结构(如 dict 差异)输出极不友好。
实操建议:
- 新项目统一用
pytest+ 原生assert,配合pytest-asyncio测异步函数 - 如果必须用
unittest,对字典比较别只写self.assertEqual(d1, d2),改用self.assertDictEqual(d1, d2),它会指出具体哪个 key 不同 - 不要用
assert True == some_func(),直接写assert some_func();也不要用assert not result代替assert result is False,后者语义更精确
最常被忽略的一点:断言要贴近被测逻辑的粒度。比如函数返回一个对象,别只断言 isinstance(ret, User),而应检查 ret.name、ret.is_active 等关键字段是否按预期赋值。







