判定测试用例通过与否
问题
如何判定API测试用例是否通过还是失败。
设计
调用待测方法,传给它测试用例的输入,得到返回值,然后比较实际结果从测试用例中读入的期望结果是否一致。
方案
string method,expected;
double actual = 0.0;
if(method == "ArithmeticMean")
{
actual = MathLib.Methods.ArithmeticMean(input);
if(actual.ToString("F4") == expected)
Console.WriteLine("Pass");
else
Console.WriteLine("*FAIL*");
}
else
{
Console.WriteLine("Method not recognized");
}
注解
从测试用例读入数据之后,需要解析这些数据,然后把测试用例输入转换成合适的数据类型,接下来就可以启用待测方法。为了让测试套件能够调用待测方法,则必须为测试套件加上一个工程引用,用以引用待测方法所在的DLL(本例中即MathLib)。上述代码首先检查这些数据要传给的是哪个方法。在.NET环境中,存在静态方法和实例方法。ArithmeticMean()是一个静态方法,因此,只要使用它的类名称作为上下文就可以直接调用它,然后把整数数组作为输入参数传给它,并且把返回结果存储到double型的actual变量。接下来,将通过方法调用得到的返回值与期望的返回值(由测试用例数据提供)进行比较。国为期望结果是string类型,而实际结果是double类型,所以必须把它们中的一个进行类型转换。在这里,将实际结果转成成小数点后有4位的string类型。其目的是为了和期望结果的格式相匹配。如果选择把期望结果转换成double类型,
if(actual == double.Parse(expected))
Console.WriteLine("Pass");
else
Console.WriteLine("*FAIL*);
那么最终比较的就是两个double值是否相等,但这是有问题的,因为double类型和float类型都只是近似值。通常的原因是:除了像本例中这样处理double或float的情况,其他情况下都应该把期望结果从string类型转换成合适的类型。
GeometricMean()是一个实例方法,所以在调用之前,必须实例它一个MathLib.Methods对象,然后通过这个对象来调用GeometricMean(),如果实际结果与期望结果一致,则测试用例通过,可以在控制台上打印一条信息:
if(method == “GeometricMean")
{
MathLib.Method m = new MathLib.Methods();
actual = m.GeometricMean(input);
if(actual.ToString("F4") == expected)
Console.WriteLine("Pass");
else
Console.WriteLine("*FAIL*");
}
通常还会希望在输入信息加上一些额外的信息,比如测试用例ID:Console.WriteLine(caseID + " Pass");
如果测试用例失败,则通常需要打印出实际值和期望值以便诊断失败的原因,例如:
Console.WriteLine(caseID + " *FAIL* " + method + " actual = " + actual.ToString("F4") + " expected = "+ expected);
编写API测试时,必须要回答一个设计问题,每个轻量级的测试套件要测试多少个方法?许多情况下,我们都会为每一个待测方法写一个测试套件;但是,也可以在一个测试套件里测试多个方法。例如,为了测试ArithmeticMean()和GeometricMean()方法,则可以将两者的测试用例数据合并到一个文件里。
0001:ArithmeticMean:2 4 8:4.6667
0002:ArithmeticMean:1 5 :3.0000
0004:GeometricMean:1 2 4 8 16 32:6.6569
0006:GeometricMean:2 4 8:4.0000
接下来可以修改测试套件的逻辑结果,用待测方法的名称来区分各个分支:
if(method = "ArithmeticMean")
{
//用于测试ArithmeticMean方法的代码
}
else if(method = "GeometricMean")
{
//用于测试GeometricMean方法的代码
}
else
{
Console.WriteLine("Unknown method");
}
是否需要把多个方法合并在一个测试套件里进行测试通常取决于这些方法的签名是否接近。如果像在配合中一样(两个方法都接受一组整数作为参数并且返回一个double值),方法的签名都非常接近,那么把它们合在一起测试就可以节省一些时间。如果方法签名相差很大,那最好还是分开写单独的测试套件。
测试API方法的时候,必须要考虑待测方法是无状态的(stateless)还是有状态的(stateful)。大多数API方法都是无状态的,也就是说各个调用之间是相互独立的。或者换种说法,调用无状态的方法,如果给定的输入一样,那么每次产生的结果都是一样。有时候我们会说无状态的方法没有记忆功能。另一方面,这些方法是有状态的,也就是说,同一组输入每次产生的返回结果可能会有所不同。例如,假设有一个方法是用来产生Fibonacci数列的,它返回前面两个整数结果的加和。因此第一次和第二次调用返回1,第三次调用返回2,第四次调用返回3,每5次调用返回5,等等,依此类推,当测试有状态的方法的时候,必须砍测试套件的逻辑符合待测方法的状态变化。
测试套件必须能够访问待测的API方法。大多数情况下,应该把包含这些API方法的DLL作为一个工程引用添加到测试程序。但是,有些情况下,则需要把待测方法的代码拷贝到测试套件里。当测试一个么有的辅助方法时,这么做是有必要的(假设你不想把该方法的访问权限从private改成public)。