多样化通常是一件好事。为什么我们这么强调物种多样性,投入那么多人力物力财力去保护濒危的动植物?就是因为,只有保持物种的多样性,生态环境才能稳定和平衡。
1956年,我国把麻雀列为四害之一,号召全民灭雀,保护粮食。全国各族人民热情高涨,积极响应,尤其是小朋友们,当时有一首诗是这么写的:“漫山遍野,天罗地网。树桠屋角,不准躲藏。昼夜不休,张弓放枪。麻雀绝种,万石归仓。”
麻雀偷吃粮食,只要麻雀绝种,就能实现万石归仓。当时人们就是这个逻辑。灭雀运动取得了巨大成功,麻雀在中国几近灭绝。但很快,大自然的反噬就出现了:没有了麻雀的制衡,蝗虫数量剧增,虫灾泛滥,比麻雀造成的损失要大得多。没办法,我国政府只好又从苏联引进了几百万只麻雀。
在测试设计的世界里,“多样化”也是非常重要的一种思想。既然我们想做的是“充分的测试”,那测试设计就应该尽量覆盖到各种不同的情况,用例就应该是多种多样的。在有限的资源条件下,每个用例都应该有足够的代表性,尽量不要跟其它用例雷同。从测试选择的角度来说,就是要让用例尽可能广泛、均衡地散布在测试输入空间里,避免“扎堆”。这样,我们才能更全面地了解被测对象在整个测试输入空间中的表现,理想和现实的对照才能更完整。
怎么做到这一点呢?最容易想到的是“随机测试”,也就是按照特定的概率分布,从测试输入空间中随机选取用例。最常见的,是遵循均匀分布的随机测试。所谓“均匀分布”,意思是每一个测试输入点被选作测试用例的概率是相同的,这样就在一定程度上实现了用例的多样性。为什么说只是“一定程度”?因为随机测试并不会考虑用例之间的差异——我同时扔3个色子,有可能扔出来的都是6点。随机测试只是通过概率的方式,间接获得了多样化的效果,但是并不敢保证效果有多好。特别是当用例数量比较少的时候,容易出现用例扎堆的情况。
随机测试经常会作为其它测试设计方法的补充:比如集成电路测试,按某个充分准则测完之后,一般都会再做一轮随机测试;再比如我们讨论过的分割测试,如果不能保证分割出来的是同质子空间,一般也需要结合随机测试。主要原因是,随机测试实施起来成本比较低,有很多简单易行的方法,能够把测试选择做成自动化的,或程式化的。
最常用的方法就是利用“伪随机数发生器”,它的基本原理是线性同余法:
给定一个起点v~0~,并给定常量a、c和m,基于上面这个递推关系,可以得到一个序列。从v~0~到v~m-1~,序列的值是随机变化的。但是从v~m~开始,序列又周而复始,所以我们把这样生成的随机数叫“伪随机数”。
JAVA自带的util.Random类,就是用线性同余法来生成随机数的。以前算命先生用梅花易数给人算卦,其实底层逻辑也是线性同余法,比如把你的生辰八字的前六个字,也就是出生年月日加起来mod 8,就可以对应到先天八卦的某一卦;再把完整的生辰八字加起来mod 8,又可以得到另一卦。把这两卦拼起来,就可以对应到易经六十四卦中的某一卦,算命先生就可以给你断吉凶了。
下面这段matlab程序实现的就是一个伪随机数发生器,可以生成1000个均匀分布的随机数:
%生成1000个[0,1]内的均匀分布随机数
function A=randomgen(a,c,m,x)
A=zeros(1000,1);
n=1;
while n<=1000
n=n+1;
x=rem((a*x+c),m); %rem(x,y):求整除x/y的余数
y=x/m;
A(n-1,1)=y;
End
如果我们把测试输入空间里的所有测试输入点编个号,然后按生成的随机数来选择,就可以实现随机测试了。
工程实践里,还有很多随机选取用例的方法,比如抓阉法、随机数色子法、随机数表法等等。