理论机制的优点
优点 1:理论(Theory)使得开发完全抽象的接口(Interface)更加容易。
优点 2:理论仍然可以重用以前的测试用例,因为以前的许多传统的具体的测试用例仍然可以被轻松的改写成理论(Theory)测试实例。
优点 3:理论(Theory)可以测试出一些原本测试用例没测出来的 bugs .优点 4:理论允许配合自动化测试工具进行使用,自动化工具通过大量的数据点来测试一个理论,从而可以放大增强理论的效果。利用自动化工具来分析代码,找出可以证明理论错误的值。
下面通过一个简单的例子来逐步介绍理论的优点。
比如设计一个专门用来货币计算的计算器,首先需要给代码行为编写测试用例(这里以英镑 Pound 的乘法为例),如清单 9 所示:
清单 9 英镑 Pound 乘法的一个测试用例
@Test
public void multiplyPoundsByInteger() {
assertEquals( 10, new Pound(5).times(2).getAmount() );
}
这时很自然的会想到一个测试用例可能不够,需要再多一个,如清单 10 所示:
清单 10 英镑 Pound 乘法的两个测试用例
@Test
public void multiplyPoundsByInteger () {
assertEquals( 10, new Pound(5).times(2).getAmount() );
assertEquals( 15, new Pound(5).times(3).getAmount() );
}
但是此时您可能又会发现这两个测试用例还是很有限,您所希望的是测试所有的整数,而不只是 2,3 和 5,这些只是您所想要的测试的数据的子集,两个测试用例并不能完全与您所想要测试的代码的行为相等价,您需要更多的测试用例,此时会发现需要很多的额外工作来编写这些测试用例,更可怕的是,您会发现您需要测试用例的并不只是简单的几个,可能是成千上万个甚至无穷个测试用例才能满足等价您的代码行为的目的。
很自然的,您会想到用清单 11 所示的代码来表达您的测试思想。
清单 11 使用变量辅助编写测试用例
//利用变量来代替具体数据表达测试思想
public void multiplyAnyAmountByInteger(int amount, int multiplier) {
assertEquals( amount * multiplier,
new Pound( amount ).times( multiplier ).getAmount() );
}
利用清单 11 的 multiplyAnyAmountByInteger 方法,可以轻松将测试用例改写成如清单 12 所示:
清单 12 改写的英镑 Pound 乘法的测试用例
@Test
public void multiplyPoundsByInteger () {
multiplyAnyAmountByInteger(5, 2);
multiplyAnyAmountByInteger(5, 3);
}
如清单 12 所示,以后若想增加测试用例,只要不停调用 multiplyAnyAmountByInteger 方法并赋予参数值即可。
方法 multiplyAnyAmountByInteger 是一个理论的简单例子,理论是一个带有参数的方法,其行为是对任何参数都是正常的返回,不会抛出断言错误和其它异常。理论是对一组数据进行概括性的陈述,像一个科学理论一样,如果没有对所有可能出现的情况都进行实验,是不能证明该理论是正确的,但是只要有一种错误情况出现,该理论不成立。相反地,一个测试是对一个单独数据的单独陈述,像是一个科学理论的实验一样。