youki吧 关注:112贴子:14,641
  • 0回复贴,共1

API 测试(转自51testing)

只看楼主收藏回复

API(Application Programming Interface)测试的自动化是软件测试最基本的一种类型。从本质上来说,API测试是用来验证组成软件的那些单个方法的正确性,而不是测试整个系统本身。API测试也称为单元测试(Unit Testing)、模块测试(Module Testing)、组件测试(Component Testing)以及元件测试(Element Testing)。从技术上来说,这些术语是有很大的差别的,但是在日常应用中,你可以认为它们大致相同的意思。它们背后的思想就是,必须确定系统中每个单独的模块工作正常,否则,这个系统作为一个整体不可能是正确的。毫无疑问,API测试对于任何重要的软件系统来说都是必不可少的。
  例:一个窗体程序,估且叫StatCalc,它可以计算一组整数值的平均值。在后台,StatCalc程序引用了MathLib.dll库,这个库包括一些用于计算平均值的方法,比如计算算术平均值的ArithmeticMean(),计算几何平均值的GeometricMean(),以及计算调和平均值的HarmonicMean()。
  我们的目标是测试上述三个方法,而不是使用了这三个方法的整个StatCalc程序。为了将待测试和用于测试它们的测试套件(Test Harness)系统区分开来,待测程序通常叫作SUT(System Under Test)、AUT(Application Under Test)或者IUT(Implementation Under Test),此例中使用AUT这个术语。
  需要进行测试的几个方法属于一个叫作Methods的类,这个类位于MathLib命名空间(namespace)内,这几个方法的定义如下:
  namespace MathLib  {  public class Methods  {  public static double ArithmeticMean(params int[] vals)  {  //计算并返回算术平均值  }  private static double NthRoot(double x, int n)  {  //计算并返回n次方根  }  public double GeometricMean(params int[] vals)  {  //使用n次方根计算并返回几何平均值  }  public static double HarmonicMean(params int[] vals)  {  //此方法未实现  }  }//class Methods
  请注意,ArithmeticMean()是一个静态方法,GemetricMean()是一个实例方法(instance method),而HarmonMean()还没有完成,并不能进行测试。如何处理静态方法、实例方法以及未完成的方法是编写轻量级的API测试自动化程序时,最常见的三种情况。每个待测方法都接受整数序列作为参数(由params关键字指明),并且返回一个double类型的值。大多数情况下,用不着测试那些辅助的私有函数,比如说NthRoot()。如果辅助函数有错误,在测试其他用到了这个辅助的方法时,会把这些错误暴露出来。但是如果辅助函数非常复杂,则最好需要用到本文讲到的技术写一个专门针对它的测试用例。
  手工测试这个API包括以下步骤:创建一个小的测试程序,把Methods类拷贝到测试程序,针对待测方法硬编码(Hard-coding)一些输入值,运行这个存根程序(stub program)以得到实际的输出结果,然后通过肉眼来比较实际的结果与期望的结果是否一致,从而决定测试通过与否,接下来再把结果记录到Excel表格或者类似的数据存储文件。要对待测方法的正确性有信心,可能要成百上千次地重复上述的测试过程。更好的方法是通过编写自动化程序来完成测试。
  自动化测试相对于手工测试有以下5个优点:
  速度:可以非常快速地运行成千上万个测试用例
  精确性:不受人为因素的干扰,比如记录错误结果
  确定性:每次都以同样的方式运行,而手工测试常常根据测试人员的不同而有细微的差别
  效率:可以在晚上也可以在白天运行,同时你可以做别的事情
  提高技能:提交测试人员的兴趣并且培养他们自身的技能,而手工测试通常是枯燥乏味的,并且提高不了什么技能。
  接下来的几篇依次讲解如下技术:准备API自动化测试程序,运行程序,保存运行结果。此外,还可以学到一些用来处理特殊情况的技术,比如有些方法会抛出异常,或者有些方法可以接受字符串作为参数。同时还讲述如何管理API自动化测试的一些技术,比如通过编程的方法用E-mail来发送测试结果。
存储用于测试用例的数据
  问题
  如何在一个简单的文本文件里创建并存储用于API测试用例的数据
  设计
  使用冒号作为分隔符的文本文件,这个文件包含 唯一的测试用例ID,一个或者多个输入值和期望结果。
  方案
  0001:ArithmeticMean:2 4 8:4.6667
  0002:ArithmeticMean:1 5 :3.0000
  0003:ArithmeticMean:1 2 4 8 16 32:10.5000
  注解
  编写自动化测试程序的时候,可以让测试用例数据独立于测试套件单独存在,也可以把它嵌入测试套件。通常来说,较好的做法是让测试用例数据独立于测试套件,因为这样做可以让多个测试程序共享数据更为容易,而且修改这些数据也更为容易。文件的每一行代表一个单独的测试用例。每个测试用例有4个字段,它们分别是:测试和例ID、待测试方法、测试用例数据输入(由空格分开),以及期望结果。这4个字段由“:”字符来隔开。很多时候,这些文件还会包含一些额外的数据,比如测试用例标题、测试用例描述以及测试用例分类。选择什么做为分隔符,大多数情况下你都可以根据自己的喜好来决定。前提是要使用的分隔符不能是输入数据或是期望结果的一部分。举例来说,用冒号作为分隔符对于测试与数值计算相关的方法来说毫无问题,但是如果所测的方法的输入是URL那就有问题了,因为"http”后面紧跟着就是冒号。对于很多轻量级的自动化测试程序来说,出于简单性考虑,文本文件就最好的数据存储方法。其他的方法还包括把测试用例数据存储到XML文件或者SQL表。使用文本文件的不足之处还在于,它们很难处理有内在层次结构的数据,而且很难识别出伪控制字符,比如<CR><LF>等。
  前在的方案只有3个测试用例,但是实际测试中,你常常需要成千上万个测试用例。应该考虑到边界值(通过给出 一些特殊的输入,比如说正好等于、小于、大于预定义的输入上限或下限)、空值以及无效输入 。还要有一些用例使用重新排列过的输入数据,如下所示:
  0002:ArithmeticMean:1 5:3.0000
  0003:ArithmeticMean:5 1:3.0000
  决定测试用例的期望结果通常是比较困难的,从理论上来说,会有一份文档详细说明待测方法的行为。当然,实际情况是:这些文档要么不全,要么根本就没有。常见的一种错误是,把输入数据提供给待测方法,记下输出结果,然后把这个结果作为期望值,你应该努力避免这种错误,因为这种做法不是在测试一个类的方法:它仅仅验证了你每次得到的都是相同的(但可能是不正确的)输出结构。如果采用这种做法,那就是无效的测试系统。
  开测试套件的过程中,应该故意创建一些产生失败结果的测试用例。这么做可以帮助我们发现测试套件中的逻辑错误。例如:
  0004:ArithmeticMean1 6:6.0000:deliberate failure
  通常来说,当待测函数或待测方法都位于DLL当中时,使用术语API测试。当待测方法位于某个类(当然,这个类可能作为一个DLL来实现)中的时候,使用术语单元测试(Unit Testing)。术语模块测试(Module Testing)、组件测试(Component Testing)以及元件测试(Element Testing)是更为宽泛的术语,当所测试的函数和方法不用DLL的方法来实现的时候,使用后面几个术语。
读入测试用例数据
  问题
  如何从测试用例文件(简单的文本文件)中读入每条测试用例。
  设计
  通过while循环遍历用例文件的每一行,使用System.IO.StreamReader对象读入测试用例。
  方案
  FileStream fs = new FileStream("..\..\TestCases.txt",FileMode.Open);  StreamReader sr = new StreamReader(fs);  string line;  while ((line = sr.Reader()) != null)  {  //解析每个测试用例行  //调用待测方法  //判断通过与否  //记录测试用例结果  }  sr.Close();  fs.Close();
  注解
  通常来说,控制台程序相比于Windows窗体程序,更适合用来编写轻量级的自动化测试程序。控制台程序很容易集成到遗留下来的测试系统,而且在Windows环境下也很容易操纵。如果你要把测试程序写成窗体程序,请不要忘了让这个程序也可以通过命令行来进行操纵。
  本方案假定已经把using System.IO;语句放到测试程序的代码里,这样就可以使用FileStream和StreamReader类而不用每次都引用它们的全名。我们还假定测试用例数据文件被命名为TestCase.txt,并且被放在测试程序所在目录的上两级目录。对于测试用例数据文件来说,相对路径通常要比诸如C:\\Here\\There\\TestCase.txt这样的绝对路径要好,因为相对路径允许把测试程序的根目录和子目录做为一个整体进行移动,而不会打乱测试程序的路径。但是,如果测试系统的目录结果改变了,那么相对路径就会打乱你的测试程序。还有一种做法是:把测试数据文件的路径和名字作为测试程序的参数:
  static void Main(string [] args)  {  string testCaseFile = args[0];  FileStream fs = new FileStream(testCaseFile,FileMode.Open);  //etc.  }
  这样一来,就可以像下面的这样调用测试程序:
  C:\\Harness\bin\Debug>Run.exe ..\..\TestCase.txt
  在本方案中,用到了FileStream和StreamReader对象,另外也可以使用System.IO.File类中的一些静态方法,如File.Open().如果预计到可能会有两个或者更多测试程序同时访问测试用例文件,可以使用重载过的FileStream的构造函数,它包含一个FileShare参数用来指定如何共享这个文件。
解析测试用例
  问题
  如何解析出由字符分隔开的测试用例的各个字段。
  设计
  使用String.Split()方法,把分隔符作为输入传给它,然后把返回值存入一个字符数组。
  方案
  string line,caseID,method;  string[] tokens,tempInput;  string expected;  whild((line = sr.ReadLine()) != null)  {  tokens = line.Split(':');  caseID = tokens[0];  method = tokens[1];  tempInput = tokens[2].Split(' ');  expected = tokens[3];  //etc.  }
  注解
  把一行测试用例数据读入一个字符串变量后,调用Split()方法,把冒号作为参数传给Split()方法,得到的结果就是原字符串中以冒号分开的各个部分,然后把这些子字符串赋给字符串数据tokens。这样tokens[0]保存的就是第一个字段,也就是测试用例ID(例如“001”),tokens[1]保存的字符串是待测方法的名称(例如"ArithmeticMean"),tokens[2]保存的是以字符串形式存在的输入向量(例如"2 4 8"),tokens[3]保存的是期望值(比如"4.667")。接下来,针对tokens[2],使用一个空格罕作为参数调用Split()方法,然后把结果赋给字符串数组tempInput,如果tokens[2]的内容是"2 4 8",那么tempInput[0]的内容就是"2",tempInput[1]的内容是"4",tempInput[2]的内容是"8"。
  如果用到了多个分隔符,则可以创建一个包含这些分隔符的字符数组,并把这个数组传给Split(),例如:
  char[] separators = new char[] {'#',':','!'};
  string[] parts = line.Split(separators);
  上述代码会把字符串变量按照"#"、":"或"!"分隔成多个子串,并且把子串赋给字符串数组parts。
  对于轻量级的自动化测试程序来说,Split()方法可以满足大多数简单文本文件的解析。如果不用Split(),另一种很好的方法就是使用正则表达式,。使用正则表达式的好处是,它更为强大,也就是说只用很少几行代码就可以完成很多的解析工作。正则表达式的一个缺点是,不经常使用它们的人很难理解,因为跟C#比起来,正则表达式的语法相对来说较为生僻。I


1楼2013-11-01 16:15回复