如何评估测试工具
以下几节将详细描述在软件测试工具的评估过程当中你应该研究的问题。理想情况下,你应该通过亲手测试正在评估的每一个工具,来确认这些信息。
由于本文下面的部分技术性很强,我们想向你解释一下下文的表述格式。对于每一个部分,我们都有一个标题来描述将要讨论的问题,一个关于该问题重要性的描述,还有一个“要点”部分来概括需要考虑的问题。
另外,除了表述格式以外,我们也应对专业术语作出注解。 “函数/方法(function)”一词是指一个C函数或C + +类的方法,“单元”是指一个C文件或C + +类。最后,请记住,几乎所有的工具都能在一定程度上支持“要点”部分中提到的问题,你的工作是评估自动化程度、易用性,以及支持的完整性。
解析器和代码生成器
要建立一个C解析器是相对容易的,但要建立一个完整的C + +解析器是非常困难的。工具评估过程中需要回答的问题之一是:“解析器技术的健壮性和成熟性如何”?一些工具厂商使用商业解析器,他们从解析器技术公司获得许可,还有一些厂商使用自主开发的解析器。使用你项目中具有代表性的复杂的代码结构来评估工具,可以验证解析器和代码生成器的健壮性。
要点:
> 解析器技术是商业外购的还是自主研发的?
> 支持哪些语言?
> C版本的工具和C + +版本的工具是否相同?
> 全部是C ++语言实现的,还是局限于其中一部分?
> 工具能测试我们最复杂的代码吗?
测试驱动程序
测试驱动程序是控制测试的“主程序”。下面是一个驱动程序的简单例子,它将用来测试标准C库中的正弦函数:
#include <math.h>
#include <stdio.h>
int main () {
float local;
local = sin (90.0);
if (local == 1.0) printf ("My Test Passed!");
else printf ("My Test Failed!");
return 0;
}
虽然这是一个很简单的例子,“手工”工具可能会要求你手工输入(和调试)这一小段代码片段,“半自动化”工具可能会给你某种脚本语言或简单的图形用户界面(GUI)来输入正弦函数的输入参数值。“自动化”工具将提供一个用于构建测试用例、集成代码覆盖率分析的全功能图形用户界面(GUI),一个集成调试器,以及与嵌入式目标环境的集成部署。
不知你是否注意到,该驱动程序有一个bug。那就是正弦函数实际上应该使用弧度值而不是度数来作为角度的输入值。
要点
> 驱动程序是自动生成的,还是自己编写的?
> 我可以不写任何代码来测试下面的内容吗:
测试覆盖一定范围的值
组合测试
数据分区测试(等价类)
输入值列表
预期值列表
预期异常值
信号处理
> 我可以在相同的测试中建立一个调用不同方法的序列吗?
为关联的函数/方法打桩
当你想控制在测试过程中关联函数/方法的返回值时,你就需要为关联函数/方法建立替代值,打桩是集成和单元测试中非常重要的部分,因为它允许你从应用程序的其它部分中隔离出被测代码,更容易触发你所感兴趣的单元或子系统的执行。
许多工具都需要手动生成测试代码,才能使得桩(stub)不仅仅只是返回一个静态的标量值(return 0;)。
要点
> 桩是自动生成的,还是你为它们写的代码?
> 是否自动支持复杂的输出(结构体,类)?
> 每次调用桩能返回不同的值吗?
> 桩会记录它被调用的次数吗?
> 桩会记录多个调用的输入参数吗?
> 你可以对标准C的库函数比如malloc打桩吗?
测试数据
“半自动化”和“自动化”工具生成测试用例的基本方法有两种。一种是“数据驱动”架构,另一种是“单一测试”架构。
对于数据驱动架构,所有被测单元都创建了测试框架,并支持在这些单元中定义的所有函数/方法。当要运行测试时,工具只是简单地通过一个数据流,如文件句柄或像一个通用异步收发器(UART)一样的物理接口,提供执行所需的测试数据。
对于“单一测试”架构,在每次运行测试时,工具都将建立该测试的测试驱动程序,编译并链接成一个可执行文件。这里有两点需要注意:首先,单一测试方法所需要的额外的代码的生成、编译和链接在测试执行的时候都将花费更多的时间;其次,你最后要为每个测试用例建立一个单独的测试框架。
这意味着候选工具可能看上去在运行一些有名无实的测试用例,但可能在更复杂的测试中却无法正确地工作。
要点
> 测试框架是数据驱动的吗?
> 执行测试用例(包括所有代码生成和编译时间)要多久?
> 可以在测试工具IDE之外编辑测试用例吗?
> 如果不能,我是否已经用复杂的示例代码充分地玩转该工具以了解工具的所有限制了?
测试数据的自动化生成
一些“自动化”工具提供了测试用例在一定程度上的自动化创建。这可以用不同的方法来完成。以下段落描述了其中的一些方法:
MMM 极小-中间-极大值测试用例
MMM的测试将重点函数/方法的输入类型的边界值。 C和C ++代码通常不会控制超出边界范围的输入值。工程师已在他们头脑中已经清楚函数/方法的值域范围,他们却往往没有控制超出边界范围的输入。
EC等价类
等价类测试为每个数据类型创建了“分区”,并从每个分区选取了一个样本值。设定相同分区中的值将以同样的方式触发应用程序。
RV随机值
随机值测试会为每个函数/方法的参数设置随机值组合。
BP基本路径测试
基本路径测试使用基础路径分析来测试贯穿被测程序的各条可能的执行路径。基本路径测试可以自动达到一个高水平的分支覆盖率。
在考虑构建自动化测试用例时,要记住的关键一点是它们使用的目的。自动化测试可以很好地用于测试应用程序代码的健壮性,而不是正确性(即使它们提供了很高的代码覆盖率)。对于正确性,你创建的测试用例必须是基于应用程序应该要做什么(测试需求),而不是基于它做了什么(代码)。
与编译器的集成
与编译器的集成需要注意两点。一点是允许测试框架(Test harness)进行自动编译和链接,不需要用户去设置编译器所需的选项。另一点是允许测试工具兼容编译器所使用的任何特定的扩展语言。尤其是交叉编译器,它们提供非C / C + +语言标准的扩展是很常见的。一些工具使用宏定义方法(#)将这些扩展定义为空字符串。这种拙劣的方法是非常不好的,因为它改变了编译器产生的目标代码。例如,考虑下面的带有GCC属性的全局外部变量:
extern int MyGlobal __attribute__ ((aligned (16)));
如果你的候选工具在定义全局变量MyGlobal时不能维持其属性不变,那么因为内存边界对齐不一样,代码在测试时和实际部署时将会表现得不一样。
要点
> 工具是否能自动编译和链接测试框架?
> 该工具是否能兼容并实施编译器特定的语言扩展?
> 编译器有什么类型的接口(IDE,CLI等)?
> 工具是否提供接口用来从你的开发环境中导入项目设置,还是必须手工导入?
> 如果该工具导入了项目设置,该导入功能是通用的还是局限于特定的编译器或编译器系列的?
> 测试工具是否和调试器集成以允许你调试测试用例?
支持嵌入式目标测试
在这一节中,我们将使用术语“工具链”来表示整个交叉开发环境,包括交叉编译器、调试接口(模拟器)、目标板和实时操作系统(RTOS)。重要的是要考虑候选工具是否能很完善地与你的工具链集成,并且要清楚如果你迁移到一个不同的工具链上,该工具中需要改变些什么。
此外,了解目标环境集成的自动化水平和健壮性也很重要。正如前面提到的:如果某个厂商说:“我们支持所有的编译器和目标板。”他们的意思是说:“你需要自己去完成让我们的工具能在你环境中运行的所有工作。”
理想情况下,你选择的工具将允许你只需点击一个“按钮”即可完成“测试执行”所涉及的所有复杂工作,包括将测试用例下载到目标环境,并将测试结果捕获到主机平台,,从而不需要用户再做任何特殊的操作。
嵌入式目标测试的另一个难题是硬件的可用性。通常情况下,硬件与软件是并行开发的,或者硬件的可用性是有限的。一个关键的特征是能否先在一个本地的环境开始测试,后期再过渡到实际的硬件环境。理想情况下,工具的使用是不受硬件条件限制的。
要点
> 能支持我的工具链吗?如果不能,那它能有办法被支持吗?“支持”是什么意思呢?
> 我能在主机系统上建立测试,然后将它们用于目标环境的测试?
> 测试框架是怎样下载到目标上的?
> 测试结果是如何被获取并返回到主机的?
> 能现成地支持哪些目标、交叉编译器和RTOS?
> 为一个新的工具链建立支持的工作由谁来完成?
> 工具链集成的任何部分都是用户可配置的吗?
测试用例编辑器
显然,使用测试工具时,你大部分的时间都会花在测试用例编辑器上。如果本文中之前提到的各方面都实现了真正的自动化,那么搭建测试环境和目标连接所占的时间量将是最小的。记得我们在开始时说的,作为工程师,你会想将更多的时间用在设计更好和更完整的测试上。
当你在评估工具时,需要回答的关键的问题是为复杂的结构设置输入和预期值有多困难?市场上的所有工具都提供了一些简单的方法来设置标量值(scalar values)。例如,你的候选工具是否提供了一个简单而直观的方式来构建一个类?用一个抽象的方法(比如一个向量或一个映射)来建立一个STL容器如何?这些都是在测试用例编辑器中要评估的问题。
本文的下面部分有“支持”,也有“自动化支持”。在评估你可能感兴趣的结构时要考虑到这一点。
要点
> 能否显示标量值范围?
> 是否显示数组的大小?
> 是否可以简单地用标签设置最小值和最大值而不用直接设值呢?这对当类型改变时保持测试的完整性是很重要的。
> 是否支持特殊的浮点数(例如,为NaN,+/ - 无穷大)?
> 你可以做组合测试(在一定范围内对5个参数取一系列不同的值,让工具来完成那些值的所有组合)吗?
> 编辑器是否支持不同“数的进制”,让你可以很容易地交替输入不同进制的数,比如十六进制、八进制和二进制值?
> 对于预期的结果,你可以很容易地为浮点值输入绝对容错范围(如+/ - 0.05)和相对容错范围(例如:+/ - 1%)吗?
> 测试数据可以很容易地从其它数据源(如Excel)导入吗?