测试中的随机性

测试中的随机性

本文章摘要自 MSDN
作者:James McCaffrey

wwwlehu6.vip乐虎官网 1

本页内容

浮动统壹的私自数字
剖析形式随机性
混排项目列表
变化正态/高斯数字
总结

创立和动用随机测试用例数据是一项基本的软件测试技术。就算抢先二分一测试用例数据由所测试系统的特定输入数据以及特定预期值/状态组成,但您大约平昔都想让系统也遭到随机测试用例输入数据的测试。平时,您那样做是为了打探向应用程序发送大量不等的输入数据是还是不是会导致系统崩溃或引发那个。在本月的特辑中,小编将演说在
Microsoft® .NET Framework 环境中处理随机测试用例数据时的七个普遍职责:

生成伪随机数字(Knuth 算法)

分析模式随机性(Wald-Wolfowitz 检验)

混排项目列表(Fisher-Yates 算法)

生成高斯数字(Box-Muller 算法)

让大家看一下图 一 中的示例。输出的率先片段显得了选拔 .NET Framework 的
Random
对象生成基本自由数字的结果。固然你或然很熟悉此情势,但自个儿还是要提议什么制止大规模缺陷。输出的第3局地反映了2个万分实用但却不敢问津的艺术,该措施用来分析由任意符号组成的情势是还是不是享有随机性。常常,该方法广泛应用于软件开发中,而不只是选用于测试方面。图
1 的第3有的表明了混排项目列表的结果,该结果充裕复杂。

wwwlehu6.vip乐虎官网 2

图 一 随机格局言传身教

自家将详细表达为啥许多混排完成方式表面上就像正确,而实际却截然错误。图
1中输出的末段壹某些注明了生成按正态钟形曲线分布的1组数字的结果。除了是一种很是实用的秘籍之外,该算法的贯彻细节凭其自个儿的性质而得以关切,将成为您个人编码工具箱的2个有价值的补充部分。

变化统1的四意数字

自由测试用例生成中的最主旨任务是生成贰个某一定值域内的专擅数字(整数或浮点数)。那1般通过
System.Random 类来兑现。假定有以下代码:

Random objRan = new Random(5);
int n = objRan.Next(7);
Console.WriteLine("[0,6] 值域中的随机整数是 " + n);

n = objRan.Next(3, 13);
Console.WriteLine("[3,12] 值域中的随机整数是 " + n);

以 Random 对象为例,传入三个种子值(在本例中为
5)。该种子值用于为显示出真正自由数字许多特征的某部数字系列设置起源。系列是明显的(这几个数字是从输入种子值或系列中前多少个数字时所用的数学公式而转变),因而由
System.Random
生成的数字从技术角度来讲是伪随机数字,但在业余使用状态下或左右文分明时,经常将其名叫随机数字(如此例所示)。笔者采用的种子值具有任意性。若是本身动用不接受种子值的重载
Random
构造函数,则将动用从系统机械钟派生的值。假设在随着测试运转时,您必要再行创建随机数字类别(常常状态是如此),则应提供一个种子值。有关伪随机数字生成器种子值的研讨是多个生死攸关且复杂的主题,抱歉的是,它不在本专栏的座谈范围内。

变化随机整数的最简易方法是调用 Random.Next
方法,传入单个整数参数。重返值是伪随机列表中的下1个整数,此值大于或等于
0 且绝对小于该参数。由此,以下调用将重返1个在于 0 和 九 之间(包蕴 0 和
九)而不是在于 0 和 十 之间(包蕴 0 和 10)的数字:

   int n = objRan.Next(10);

Random.Next
方法的重载将接受四个整数参数并回到三个压倒或等于首个参数且相对小于第二个参数的整数。假若你要效仿的测试用例数据类似于滚动的常备陆面骰子,要拿走2个在于
一 和 陆 之间(包蕴 壹 和 陆)的任性数字,则调用可能如下所示:

int roll = objRan.Next(1, 7);

那很不难从某数组生成三个随便选用项:

string[] items = new string[] { "alpha", "beta", "gamma", "delta" };
Console.WriteLine("{ 'alpha', 'beta', 'gamma', 'delta' } 的" +
    "随机成员是 " +
    items[objRan.Next(items.Length)] );

假定数组大小为 N,则调用 objRan.Next(N) 所生成的再次来到值将是值域 [0,
N-1]
内的三个平头(该值域完全对应于数组的索引值)。请小心,该情势也可用以
ArrayList 对象,而且实际也可用于其余以 0 为基数的索引化集合。

在后台,重载的 Random.Next 方法将应用 Knuth
伪随机数字生成方法。那也称之为“相减法”。Knuth 在《The Art of Computer
Programming》(总括机程序设计方法)(艾狄生-韦斯利, 一九8四) 第 二卷的“Seminumerical
Algorithms”(陆1%值算法)中刊登了此算法。生成统一的伪随机数字非凡有难度,但正是.NET Framework 会负责为你落成 Knuth 算法。

差不离在第3遍支付 .NET Framework 时,Matsumoto 和 Nishimura
就意识了一种新的伪随机数字生成算法。他们的算法一般被称作 Mersenne
Twister(马其赛特旋转)方法,并正因其日常所具备的卓著品质和数学天性而高速取代原来的伪随机数字生成算法。请参阅“Mersenne
Twister:A 6二三-Dimensionally Equidistributed Uniform Pseudo-Random Number
Generator”,《ACM Transactions on Modeling and Computer
Simulation》(美利哥总计机学会模型和处理器仿真汇刊),第 八 卷,第 一号,一9九陆 年 一 月。

变化伪随机浮点数与转移伪随机整数类似。假定有以下代码:

double x = (6.25 * objRan.NextDouble()) + 1.50;
Console.WriteLine("[1.50,7.75) 值域中的随机双精度值是 " +
                  x.ToString("0.00"));

对 Random.NextDouble 的调用将回到三个超乎或等于 0.0 且相对小于 一.0
的数字。要扭转在值域 [下限值,上限值)
之内(当中,八个括号符号表示大于或等于“下限值”且相对小于“上限值”)的浮点型数字,则可应用小型公式:

double result = ((high-low) * objRan.NextDouble()) + low;

因为除 0.0
外,超过百分之五十浮点型数值都为接近值,所以从技术上说,您无法在含有端点值的值域
[wwwlehu6.vip乐虎官网,下限值,上限值] 内生成浮点型数字,而必须将其改为不带有端点值的值域
[下限值,上限值)。该公式与接受完全值域的 Next
重载中所用的公式大约相同,只不过转换为整数的结果不一致。

分析形式随机性

突发性,您只怕需求检讨有个别测试用例输入或输出格局,以表明它是随机生成的(例如,检测并规定某壹赌钱模拟事实上正输出随机结果)。有多少个总结方法可用于完成此目的,但最简便易行的是
Wald-沃尔夫owitz
检测。该检查有时称为单样本游程检查测试(个中,“游程”为浩如烟海一致数字或字符)。Wald-沃尔夫owitz
检查评定适用于由四个标志组成的种类,例如:

A B B A A A B B B A B B

其中的法则是,对于形式中钦点数量的每一个符号类型(共三个记号类型),假使符号为随意变化(在本例中,意味着方式中每种岗位出现A 或 B 的概率各为
50%),则您可总括该情势中的预期游程数。格局游程是三个由同样符号类型组成的队列。因而,在刚刚所示的形式中,共有八个游程:A、BB、AAA、
BBB、A、BB。倘若方式中的实际游程数过大或过小,则表明该情势不是随机变化。

固然 Wald-沃尔夫owitz
检查测试仅适用于只包括二种标志类型的形式,但您常常可以将随意方式映射为
Wald-沃尔夫owitz 情势。例如,假诺您有七个 {柒, 玖, 三, 4, 一, 陆}
之类的整数连串,则能够算出其平均值为 (5.0),然后将该体系映射到符号 H 和
L,在那之中 H 代表大于该平均值的数,而 L 代表小于该平均值的数:H H L L L
H。假诺你须要分析更扑朔迷离的格局,则足以行使 Chi-Square 检查测试或 Kolmogorov
检查实验之类的一对检察方法。

如今,让大家只要 n一 是某方式中第3种标志的多寡,而 n二是第两种标志的数据。则随机变化形式中的预期游程数 µ 为:

µ = 1 + ((2*n1*n2) / (n1 + n2))

而方差 α贰 由下式算出:

α2 = ((2*n1*n2) * (2*n1*n2 - n1 - n2)) / ((n1 + n2)2 * (n1 + n2 - 1))

这两个公式均根据概率论得出。我们可以用平均值和方差来确定某个特定模式是随机过程结果的概率。假设我们以两个符号的模式开始,该模式表示为以下字符串: 

string s = "XOOOXXXXOXXXXXXXOOOOXXXXXXXXXX";

固然能够手动统计该形式中 X 和 O
的数量以及游程数,但让自家的主次代劳会更轻松。首先,笔者将规定该格局字符串中的多个标志类型:

char kind1 = s[0], kind2 = s[0];
for (int i = 0; i < s.Length && kind1 == kind2; ++i) 
{
    if (s[i] != kind1) kind2 = s[i];
}

小编将形式字符串中的第三个字符钦定给第一种标志,接着扫描整个方式字符串,直到找到第二种标志类型。接下来,将推行两项简单的荒唐检查,以保障该格局中至少存在二种不一样字符并且存在的字符类型不超过三种。

if (kind2 == kind1)
    throw new Exception("字符串必须具有两种不同的类型");

for (int i = 0; i < s.Length; ++i)
    if (s[i] != kind1 && s[1] != kind2)
        throw new Exception("字符串只能具有两种类型");

借使要思量品质,则可将那二遍对形式字符串的遍历重新更换为单独二遍遍历,但清晰性可能会遭到1些震慑。

今昔,笔者就能够起头估计形式中每类别型符号的数目以及游程数了:

int n1 = 0, n2 = 0, runs = 1;
for (int i = 0; i < s.Length-1; ++i)
{
    if (s[i] == kind1) ++n1;
    else if (s[i] == kind2) ++n2;
    if (s[i+1] != s[i]) ++runs;
}
if (s[s.Length-1] == kind1) ++n1;
else if (s[s.Length-1] == kind2) ++n2;

自家从第一个字符开端扫描该形式,平素频频到尾数第三个字符。如若当前字符与本人在此以前规定的标志类型相配,则自身将递增相应的计数器。为总结格局中的游程数,笔者动用了游程取决于符号类型的转变的那样三个真情。如若当前字符与下三个字符区别,则自身就明白又冒出1个游程,然后本身将相应递增游程计数器。由于我在情势字符串中的尾数第一个字符处甘休,因而最终本人要检查最终叁个字符。小编还会从
一(而不是
0)早先一共游程计数器,因为依照定义,全体方式都至少存有二个游程。

Wald-沃尔夫owitz 检测方法仅在所分析形式中每类别型符号的数量为 八 或当先 8时才使得,因而小编将履行以下检查:

if (n1 < 8 || n2 < 8)
    throw new Exception("n1 和 n2 必须均大于等于 8," +
                        "本次测试才有意义");

解析进度进展到那时候,笔者已算出形式中二种标志类型中每一种的数量以及实际游程数。今后,如果五个记号类型是随机变化,则自个儿将总计方式中的预期游程数:

double expectedRuns = 1 + ((2.0*n1*n2) / (n1 + n2));

下一场本人将总结游程数的方差(假设任意生成),如下所示:

double varianceNumerator = (2.0*n1*n2) * (2.0*n1*n2 - N);
double varianceDenominator = (double)((N*N)*(N-1));
double variance = varianceNumerator / varianceDenominator;

浅析中的下一步是持筹握算原则检查实验总计量 z:

double z = (R - expectedRuns) / Math.Sqrt(variance);

z
总结量等于形式中的实际游程数减去方式中的预期游程数,然后再除以预期游程数的专业不是(即方差的平方根)后所获得的值。解译情势中的标准化游程数要比解译实际游程数简单。解译代码很简短,但在概念上有点有点别扭。它的发端如下所示:

if (z < -2.580 || z > 2.580)
{
    Console.Write("充分证明 (1%) 模式不是随机生成的:");
    Console.WriteLine(z < -2.580 ? "游程太少。" : 游程太多。");
}

笔者以百分之壹的鲜明性水平执行了1次所谓的双侧检查实验。如若基准检查实验计算量的断然值当先贰.580,则不严苛地说,那代表所分析情势由任意进程生成的概率不到百分之1。值
二.580
源自总计表。假如查看总括量为负值,则实在游程数稍低于预期游程数,反之亦然。在图
2中,小编也在查找注解该情势不是随机生成的不足够证据。请留意,您在任什么日期候都不可能肯定地说给定形式是随机生成的;您不得不通过检查来了然是不是留存总结证据来表达该情势不是随机生成的。

混排项目列表

让大家研讨一下混排项目列表。假若你有多个测试用例输入集合并且想以自由顺序将其总体输送到所测试系统中,则混排项目列表很有用。您能够将混排列表看作是转变项目标妄动排列。这么些尤其困难的题材曾是大方钻探工作的宗旨。最棒的通用混排算法称为
Fisher-Yates 算法。有时候也叫做 Knuth
混排算法。那种算法极其不难。借使有二个项目数组:

string[] animals = new string[] { 
    "ant", "bat", "cow", "dog", "elk", "fox" };

假如用 Fisher-Yates 算法的最常用方式来混排那列动物,将得到以下内容:

for (int i = 0; i < animals.Length; i++)
{
    int r = objRan.Next(i, animals.Length);
    string temp = animals[r];
    animals[r] = animals[i];
    animals[i] = temp;
}

本身迭代要混排的数组的每二个目录。我在现阶段目录和数组结尾之间接选举用1个随意地点,然后换来当前目录和随机索引处的类型。不正确的混排算法分外广阔。下边包车型客车例子就越发困难。思虑一下此品尝:

for (int i = 0; i < animals.Length; i++)
{
    // int r = objRan.Next(i, animals.Length); // 正确
    int r = objRan.Next(0, animals.Length);    // 不正确
    string temp = animals[r];
    animals[r] = animals[i];
    animals[i] = temp;
}

此代码将扭转并施行,但结尾所得的重排列表将偏向于项指标一点种排列。为例示那种境况,借使要混排的原始列表中唯有多个类型,即
{ABC}。混排的目标是发出那多少个门类的任性排列,个中每个排列的爆发可能率都均等。
3

中的表显示了使用刚才所示的不科学混排算法后发出的全体 二7 种大概的结果。


3

中的表中的率先行表示,第二回迭代整个混排循环时,i 的值为 0,并且随机索引
r 的值为 0。由于起首列表为 {ABC},因此沟通后的列表仍为
{ABC}。第三次迭代时,i 为 一 且随机索引为 0。交流后,列表现在为
{BAC}。最终叁回迭代时,i 为 三 且随机索引为 0。交流后,最终列表排序为
{CAB}。那两个连串设有各个恐怕的结尾排列。假设你要计算
4

的表中每一个结果出现的次数,则将取得以下结果:

{ABC} = 4 次
{ACB} = 5 次
{BAC} = 5 次
{BCA} = 5 次
{CAB} = 4 次
{CBA} = 4 次

换言之,并不是负有排列的发出可能率都等于。请留心,A 在首先个岗位出现 五回,B 在率先个任务出现 十 次,C 在第一个职位出现 7回。借使在赌钱娱乐模拟中应用那种不正确的混排算法,则会发生严重的标题。

借使应用科学的搅和算法,您最终或许获取的结果如
4

中所示(注意 r 值一向相当大于 i
值)。此时,那多个项指标七种只怕的终极排列中每1种排列的发生可能率都以很是的,某字母现身在某一定岗位的概率也是相等的。同时还要小心,不要求开始展览第1遍遍历,因为它只会与投机交流数组中的最后三个值。因而,正确算法中的循环可转到
animals.Length – 一 而不是 animals.Length。

转移正态/高斯数字

自身将在本月特辑中示范的第多样艺术是从钟形分布(经常号称正态或高斯分布)中生成数字。

假使你要生成一些与一组人身高绝对应的测试用例输入数据。可经过一种叫做
Box-Muller 算法的特别巧妙的艺术来生成正态分布的伪随机数字。用于创建图 1中所示输出的代码的早先如下所示:

Gaussian g = new Gaussian();
double ht;
int outliers = 0;
Console.WriteLine("从平均值为 68.0 英寸、标准偏差为 6.0 英寸的" +
                  "正态/高斯分布生成 " +
                  "100 个随机身高 ->");

本人以二个程序定义的高斯对象为例。此指标实行全体工作并运用 Box-Muller算法。可变身高将受1个正态分布值的自律。作者还会初阶化二个计数器以跟踪非平常值,即那多个远不止或远低于平均身高的值。跟踪非通常值使本身最少能够证实自个儿的随机身高事实上是正态分布的。
5

列出了变化并呈现本身的自由职业身份高的代码。

作者每隔 十 个值就用模数 (%)
运算符打印2个新行,只是为了维持出口整齐。来自平均值为 68.0
英寸、标准不是为 陆.0 英寸的正态分布随机身高通过 Gaussian.NextGaussian贰方法的调用再次来到,作者稍后将对此详细表明。小编通过监督小于 5陆 英寸或超出 80
英寸的值来跟踪非寻常值。那些值是出乎或低于平均值 6捌.0
英寸五个规范不是(6.0 * 2 = 1二.0
英寸)的值。据计算,随机生成值当先平均值五个正(或负)标准不是的概率大致有
5%。因而,假如生成 100 个随机身高(就好像小编明天那般),则能够预想约有 八个非平时值。假诺得出的非平常值远多于或远点儿 多少个,则就须求密切检查代码。请小心,在图 1 所示的周转示例中,笔者刚好收获 四个有有失常态态值,那使自个儿越来越坚信自个儿的任性生成的身高数据点实际上是正态分布的。

Box-Muller 算法隐含的规律非凡深奥,但结果却是相当不难。假若你在 [0,一)
值域内有多少个相同的自由数字 U一 和
U二(如本专栏中率先某个所述),则您能够选择以下八个等式中的任叁个算出1个正态分布的即兴数字
Z:

Z = R * cos( θ )
or
Z = R * sin( θ )

其中,

R = sqrt(-2 * ln(U2))
and
θ = 2 * π * U1

正态值 Z 有三个相当 0 的平均值和一个对等 一的正式不是,您可选用以下等式将 Z 映射到八个平均值为 m、标准不是为 sd
的总计量 X:

X = m + (Z * sd)

以 NextGaussian 方法完毕高斯类的最简便易行方法由
6

中的代码表示。

本人使用的是 Math.Cos 版本,但自个儿本完全能够轻松地选择 Math.Sin
版本。该兑现代码即便实惠,但功用非常低。由于 Box-Muller 算法可选择 sin 或
cos 中的任3个函数总结正态分布的 Z 值,由此笔者倒不就好像时计算多个 Z
值,保存第二个 Z 值,然后在第3次调用 NextGaussian
方法时能够搜索所保存的值。此类完结方式如
7

所示。

就算该格局可行性很好,但也存在部分低效性。使用 Math.Sin、Math.Cos 和
Math.Log
方法开始展览测算会下跌质量。1种进步效能的高明方法是应用数学技巧。假如您检查一下
BMWX三 和 θ
的概念,会发觉它们与某单位圆内某随机点的极坐标相呼应。该数学技术正是计量单位正方形内某随机点的坐标(制止了调用
Math.Sin 和 Math.Cos
艺术)并规定该随机点是还是不是在单位圆范围内。假使是那般,大家就能够使用那组坐标;假设不是这么,则大家可计算一组新的妄动坐标,然后重试三次。约有
7八%
的随机生成坐标都在单位圆范围内,那提供了越来越好的习性,但肯定要影响到清晰性。

图 捌 中例示了单位星型技巧。Box-Muller 基本算法将精选叁个极坐标为 (科雷傲,
θ)
并确定保障在单位圆范围内的点。您也能够在包围单位圆的单位长方形内选择矩形坐标;点
(x壹, y1) 在单位圆范围内,可是点 (x2, y2) 则在单位圆范围之外。
9

表明了单位长方形方法的落到实处。

wwwlehu6.vip乐虎官网 3

图 八 单位星型技巧

在软件测试场景中,质量1般不是关键的思考要素,因此小编所提到的两种实现格局都适用。但在软件开发中,尤其是在举办模拟时,质量就改成二个重点难点。即便Box-Muller算法执行起来既高效又相对简便易行,然则也有其余代表算法可生成正态/高斯伪随机数字。有一种高效的替代格局称为
ziggurat 方法。

总结

让自身进行一下归纳计算。生成随机测试用例输入数据是着力的软件测试技术。.NET
Framework 包涵贰个 System.Random
类,可用来转移某1一定值域内的统一分布的整数型或浮点型伪随机数字。必要注意的关键难点尽管要保障正确内定值域的端点值。

可利用 Wald-沃尔夫owitz
检查评定方法来分析包含多少个记号的格局以证实它是随机生成的情势。您可使用此检查测试方法分析随机测试用例输入数据或分析所测试系统的出口数据。

极品通用混排算法称为 Fisher-Yates
算法。它相当简单并且大约不需求利用另壹种办法。但尽管正确算法中设有一丝微小偏差都大概导致算法看似天经地义但却存在首要失实。

可选取 Box-穆勒 算法生成正态分布的伪随机数字。博克斯-Muller算法隐含的数学原理11分深奥,但贯彻进度却尤其简单。有三种方式可用于贯彻
Box-Muller 算法,但都是减低功效来增长清晰性。

请将您的难点和意见通过 testrun@microsoft.com 发送给 James。

詹姆士 McCaffrey 研究生供职于 Volt Information Sciences
Inc.,在那里她负责管理 Microsoft 的软件工程师的技术培训。他早就为多种Microsoft 产品效过力,包涵 Internet Explorer 和 MSN Search。可透过
jmccaffrey@volt.comv-jammc@microsoft.com 与 James 联系。

本文章摘要自 MSDN

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图