这背后道理很简单,就是用一些随机生成的数字来驱动你的测试过程。像下面的代码,就是随机生成的数字来确定数据的顺序和参数:
Random random = new Random ();
int count = random.nextInt (10000);
for (int i = 0; i < count; i++) {
boolean add = random.nextBoolean ();
if (add) {
list.add (random.nextInt(list.size ()), new Integer (random.nextInt (100)));
} else {
list.remove (random.nextInt (list.size ()));
}
}
通过随机的产生测试数据,总有可能碰到源代码预想不到的情况。这样也就发现了代码的隐患。
无法复现?
如果一个测试能报出bug但是这个bug却不能复现,那确实是很遗憾觉得不明不白的。随机测试比较麻烦的就是随机产生的数值序列看似没有规律的,初次接触的人一来确实不达能摸到规律。终极武器还是得看源码!!! 其实Random生成的数值序列,都是由Seed确定的,而默认的seed是System.currentTimeMillis().解决方案也就明朗了,找到seed,因此 我们在项目这样组织随机测试的代码: private void doRandomOperations (long seed) throws Throwable {
Random random = new Random (seed);
try {
// do the random operations
} catch (AssertionFailedError err) {
AssertionFailedError ne = new AssertionFailedError ("For seed: " + seed + " was: " + err.getMessage ());
throw ne.initCause (err);
}
}
public void testSomeNewRandomScenarioToIncreaseCoverage () throws Throwable {
doRandomOperations (System.currentTimeMillis ());
} 我们在报错信息中加入seed信息后,事情就变得明朗了。 这只是第一步,我们暂且叫做定位随机错误。接下来,我们回到传统的回归测试,加入: public void testThisUsedToFailOnAuthorBirthday () throws Throwable {
doRandomOperations (105730909304L);
}
当然我们可以更进一步把测试代码写得更人性一点:把seed 翻译成具体操作的序列。这里就留给读者了。