第4章 测试哪些内容:Right-BICEP
4.1 结果是否正确 Right-BICEP
如果代码能够运行正确,我要怎么才知道它是正确的呢
如果你不能很好地回答这个问题,那么编写代码——或者测试——完全就是在浪费时间。
在代码的整个生命期中,“正确”的定义可能会不断在变;但是无论如何,你至少需要确认代码所做的和你的期望是一致的。
·使用数据文件
对于许多有大量测试数据的测试,你可能会考虑用一个独立的数据文件来存储这些测试数据,然后让单元测试读取该文件。
多注意一下测试数据。经验告诉我们,测试数据比代码更有可能是错的,特别是人工计算的,或者来自原有系统计算结果的测试数据。因此,当测试数据显示有错误发生的时间,你应该在怀疑代码前先对测试数据检查两三遍。
一个原则是:对于验证被测方法是正确的这件事情,如果某些做法能够使它变得更加容易,那么就采纳它吧。
4.2 边界条件 Right-BICEP
找边界条件是做单元测试中最有价值的工作之一,因为bug一般就出现在边界上。一些需要你考虑得条件有。
·完全伪造或者不一致的输入数据,例如一个名为“!*W:X\&Gi/w~>g/h#WQ@”的文件。
·格式错误的数据,例如没有顶层域名的电子邮件地址就像fred@foobar这样的。
·控制或者不完整的值(如0, 0.0, “”和null)。
·一些与意料中的合理值相去甚远的数值。例如一个人的岁数为10000岁。
·如果要求的是一个不允许出现重复数值的list,但是传入的是一个存在重复数值的list。
·如果要求的是一个有序list,但是传入的是一个无序的list;或者反之。例如,给一个要求排好序的算法传入一个未排序的list——甚至一个反序的list。
·事情到达的次序是错误的,或者碰巧和期望的次序不一致。例如,在未登录系统之前,就尝试打印文档。
一个向导可能的边界条件CORRECT。对于其中的每一条,都应该想想它是否与存在于被测方法中的某个条件非常类似,而当这些条件被违反的时,出现的又是什么情况。
·Conformance(一致性)——值是否和预期的一致。
·Ordering(顺序性)——值是否如应该的那样,是有序或者无序的。
·Range(区间性)——值是否位于合理的最小值和最大值之内。
·Reference(依赖性)——代码是否引用了一些不再代码本身控制范围之内的外部资源。
·Existence(存在性)——值是否存在(例如,是否是非null,非0,再一个集合中等等)
·Cardinatity(基数性)——是否恰好有足够的值?
·Time(相对或者绝对的时间性)——所有事情的发生是否是有序的?是否是在正确的时刻?是否恰好及时?
4.3 检查反向关联 Right-BICEP
对于一些方法,我们可以使用反向的逻辑关系来验证它们。
要注意的是:当你同时编写了原方法和它的反向测试时,一些bug可能会被在两个函数中都出现的错误所掩盖。在可能的情况下,应该使用不同的原理来编写反向测试。
4.4 使用其他手段来实现交叉检查 Right-BICEP
通常而言,计算一个量会有一种以上的算法。我们可能会基于运行效率或者其他的特性,来选择算法。那是我们要在产品中使用的;但是在测试用的系统中,可以使用剩下算法中的一个来交叉测试结果。当确实存在一种经过验证并能完成任务的算法,只是由于速度太慢或者太不灵活而没有在产品代码中使用,这种交叉检查的技术将非常有效。
另一种办法就是:使用类本身不同组成部分的数据,并且确信它们能和“合起来”。
4.5 强制产生错误条件 Right-BICEP
在真实世界中,错误总是会发生:磁盘会慢,网络连线会断开,电子邮件会多的像掉进了黑洞,而程序会崩溃。你应当能够通过强制引发错误,来测试你的代码是如何处理所有这些真实世界中的问题的。
4.6 性能特性 Right-BICEP
一个检查起来会很有益处的部分是性能特性,而不是性能本身。
你也许需要一些测试辅助工具。它们嫩构提供对单个测试进行计时,模拟告负在情况之类的功能,比如免费的JUnitPerf。