软件单元测试中的“断言”——从石器时代到黄金时代
首先,我们来介绍一些关于断言的知识。对于有经验的程序员,请移至下面的“断言”进化史部分。
在单元测试中,程序员预测程序运行到某个节点时,需要判断必须满足某些逻辑条件,才能进行下面的某些业务逻辑。如果不满足,程序会“报错”甚至“崩溃”。比如一个程序负责“转账”。在实际开始转账操作之前,需要“断言”这个账户是一个“合法”的账户,例如,账户不为空。当有事情发生时,程序开发者可以第一时间知道问题所在,并进行调试,而不是等到交付给用户后才发现问题。事实上,这个功能是TDD(测试驱动开发)的基石之一。
起初,一些单元测试框架(如JUnit)提供了断言语句,以确保程序中某处的逻辑关系必须返回true。如果不为真,则单元测试失败。下面是一个例子。如果程序运行到这一行时返回false,程序将抛出一个错误(如下图1所示)并停止运行。开发人员可以检查为什么会出现这个问题。非常简单粗糙。
除了简单之外,上面的断言还有一个问题,就是触发断言时显示的错误消息不是很友好。如上图1所示,我只是知道有点不对劲,但是没有太多有用的信息。比如最好能显示X和Y的值,这样我就能更快的明白为什么会出问题。后来出现了支持断言的单元测试框架升级版,提供了一系列高级的“断言”语句,增加了一些更友好的程序接口,也提供了更友好的错误消息。例如,下面的示例使用了两个独立的断言语句。
执行的结果如下面的图2所示。你可以看到这个错误结果与上面的“石器时代”相比已经包含了很多有用的信息,比如知道断言失败,显示预期值和实际值。
但是上述方法有一个缺点,就是大量预设的断言方法(比如判断一个方法相等,判断一个方法不相等等等。)来支持各种场景。然后出现了一个新的解决方案,其明星是Hamcrest的框架(其实这个单词是一个叫做angram的文字游戏,就是改变一个原单词中的字母顺序,这个Hamcrest是Matchers的改造)。它由Matcher在assertThat组合上使用。
这有几个优点,
说了这么多,你是不是觉得一个平时经常用到的看似简单的断言,还有很多可以深挖的地方?这只是为了吸引玉石。如果你有任何想法或建议,请使用以下方法。