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 会更合适。

小技巧:如果比较的是浮点数,别用 assertEqual。浮点运算有精度问题,用 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。

避坑指南:我曾经在测试一个函数返回值时,用 assertTrue 检查结果是否为 None。结果函数返回了空字符串 '',assertTrue('') 居然通过了!因为空字符串是 False。正确的做法是用 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 正则匹配 检查日志、错误消息格式
核心原则:断言越具体,测试失败时给你的信息就越多。能用 assertEqual 就别用 assertTrue,能用 assertIn 就别自己写循环判断。

3.5 知识体系图

下面这张图帮你理清 unittest 断言的整体脉络:

unittest 断言体系 值比较 assertEqual assertNotEqual assertAlmostEqual 布尔判断 assertTrue assertFalse assertIsNone 异常检查 assertRaises assertWarns assertLogs 核心原则:断言越具体,调试越轻松 能用 assertEqual 就别用 assertTrue

3.6 实战建议

最后分享几个我自己的经验:

  • 每个测试只测一个点。一个测试方法里塞五六个断言,失败了都不知道是哪个条件没满足。拆开写,每个方法名就说明它在测什么。
  • 断言消息要写清楚。assertEqual(a, b, msg="a 应该等于 b,但实际 a={a}, b={b}")。测试失败时,这个消息能帮你省下半小时的排查时间。
  • 别滥用 assertTrue。我见过有人写 self.assertTrue(a == b and c in d),这种写法一旦失败,你根本不知道是哪个条件出了问题。拆成两个断言,或者用 assertEqual 替代。
我的习惯:写测试时,先想「这个测试失败了我希望看到什么信息」,然后选择最合适的断言方法。这样写出来的测试,既是测试用例,也是活文档。

好了,unittest 的断言方法就聊到这儿。记住,断言不是越多越好,而是越精准越好。下一节咱们聊聊怎么用这些断言搭建一个完整的测试套件。

可可精品资料库