3. unittest断言:TestCase类提供的断言方法
说到单元测试,断言就是那个「一锤定音」的家伙。你写了一大堆测试代码,最后靠什么判断对错?就是断言。Python 的 unittest 框架里,TestCase 类给我们准备了一套相当完整的断言工具。我个人习惯把它们分成三类:值比较、布尔判断、异常检查。咱们一个一个来看。
3.1 值比较:assertEqual 与 assertNotEqual
这是最常用的两个断言。说白了就是检查「实际结果」和「预期结果」是否相等。
import unittest
class TestMathOps(unittest.TestCase):
def test_add(self):
result = 1 + 1
self.assertEqual(result, 2) # 通过
self.assertNotEqual(result, 3) # 通过
嗯,这里要注意:assertEqual 用的是 == 比较,不是 is。所以对于列表、字典这种可变对象,它比较的是值,不是内存地址。我在项目中遇到过有人用 assertEqual 比较两个大列表,结果因为元素顺序不同导致测试失败——其实用 assertListEqual 会更合适。
assertAlmostEqual 更靠谱。
3.2 布尔判断:assertTrue 与 assertFalse
这两个方法用来检查条件是否为真或假。你想想看,很多场景下我们并不关心具体值,只关心「这个条件成立吗?」
def test_boolean(self):
self.assertTrue(10 > 5)
self.assertFalse([]) # 空列表是 False
self.assertTrue([1, 2]) # 非空列表是 True
我曾经踩过一个坑:用 assertTrue 去检查两个对象是否相等。比如 self.assertTrue(a == b),如果测试失败,你只能看到「False is not True」,完全不知道 a 和 b 具体差在哪。所以,能明确比较值的场景,优先用 assertEqual。
assertIsNone。
3.3 异常检查:assertRaises
这个断言很有意思。它不检查「正常情况」,而是检查「异常情况」。比如你的函数在输入非法参数时应该抛出 ValueError,那你就用 assertRaises 来验证。
def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b
class TestDivide(unittest.TestCase):
def test_divide_by_zero(self):
with self.assertRaises(ValueError):
divide(10, 0)
这里用了 with 语句块,代码看起来更清晰。当然,你也可以用上下文管理器的方式:
def test_divide_by_zero_alt(self):
self.assertRaises(ValueError, divide, 10, 0)
我个人更推荐 with 写法,因为你可以精确控制哪段代码应该抛出异常。我在项目中遇到过一种情况:测试代码里不小心在 assertRaises 之前就调用了函数,结果异常提前抛了,测试反而通过了——这种 bug 特别隐蔽。
3.4 其他常用断言
除了上面三个核心方法,unittest 还提供了不少「专治各种不服」的断言。我整理了一张表,方便你查阅:
| 断言方法 | 检查内容 | 使用场景 |
|---|---|---|
| assertIs / assertIsNot | 是否是同一个对象(is) | 检查单例、缓存对象 |
| assertIn / assertNotIn | 成员是否在容器中 | 检查列表、字符串包含关系 |
| assertIsInstance | 对象类型 | 检查工厂方法返回值类型 |
| assertGreater / assertLess | 大小比较 | 性能测试、时间比较 |
| assertRegex | 正则匹配 | 检查日志、错误消息格式 |
3.5 知识体系图
下面这张图帮你理清 unittest 断言的整体脉络:
3.6 实战建议
最后分享几个我自己的经验:
- 每个测试只测一个点。一个测试方法里塞五六个断言,失败了都不知道是哪个条件没满足。拆开写,每个方法名就说明它在测什么。
- 断言消息要写清楚。
assertEqual(a, b, msg="a 应该等于 b,但实际 a={a}, b={b}")。测试失败时,这个消息能帮你省下半小时的排查时间。 - 别滥用 assertTrue。我见过有人写
self.assertTrue(a == b and c in d),这种写法一旦失败,你根本不知道是哪个条件出了问题。拆成两个断言,或者用assertEqual替代。
好了,unittest 的断言方法就聊到这儿。记住,断言不是越多越好,而是越精准越好。下一节咱们聊聊怎么用这些断言搭建一个完整的测试套件。