建立单元测试标准

来源:互联网 发布:单片机光耦隔离电路 编辑:程序博客网 时间:2024/04/16 06:33
 
建立单元测试标准
 
陈能技
2007-10-14
 
原文:Establishing Unit Test Criteria – Alan S.Koch
 
是时候出新版本了。那么应该把什么包括进来?显然,它应该包括每个模块的最新的最好的版本。对吧?
 
“最新的和最好的”基于一个假设:最新的版本就是最好的版本。最新的版本添加了特性,纠正了问题,简而言之,改进了之前的版本。怎么会不是最好的呢?
 
但是,实际上,事情并不是你想象的那么简单。那些新的特性可能与其它现有的功能不兼容。用户依赖的东西可能消失了。新的特性可能削弱了可用性(尤其是对新用户来说)。还有,那些bug总是在这些新的改变的代码中出现。
 
因此,我们如何才能判定最新的就是最好的?我们如何知道代码真的准备好了被包括到下一个build中?很多开发组通过建立升级标准来解决这个问题。升级标准是关于某个模块是否准备好包括在一个build版本中的判定策略。
 
单元测试标准
虽然可以把很多别的东西包括到你的升级标准中来,但是单元测试是所有这些标准的基础。几乎每个组织都假设软件开发人员在做适当的单元测试。但是不幸的是,不同的人对“适当”的测试倾向于采用非常不一样的理解。
 
好的实践要求开发人员文档化它们的测试,并且对那些测试进行同行评审以确保有适当的覆盖率。如果使用自动化测试,那么开发人员能简单地为开发工具创建测试脚本,并且提交那些脚本用于评审。
 
当然,对于什么应该包括在单元测试中必须建立一个小组的标准。作为一个开发组,关于应该做什么测试要达成一致的共识需要花费一些时间和做出一些权衡,但是花在这里的时间会从正确的构建过程中得到加倍的回报!让我们看看一些单元测试期望的例子。
 
功能
当然,每个模块必须被测试以确保它满足设计的要求,并且确保它做了真正应该做的正确的事情。它应该处理什么样的输入?必须完成什么工作?会提供什么服务?它应该产生怎样的输出?它必须管理什么数据,应该怎样使用那些数据?我们必须确保这个模块真正做了它需要做的事情。
 
负面测试
然后是错误处理。当出现错误时这个模块会做“正确”的事情吗?当它处理某些特殊的输入时会出现什么情况?缺乏数据组成或数据输入的顺序被打乱的时候会怎样?当需要输入数值数据时给它非数值数据会怎样?数据溢出?如果它接收到一个从数据库或网路接口返回的错误状态时会怎样?它会如何处理?一个模块在被认为完成之前,必须正确地处理所有错误条件。
 
覆盖
我们都知道完全的测试不是软件测试的一个合理目标。太多的输入组合,事件的发生有太多的可能顺序,太多不同的出错方式,因此完整地测试所有东西,即使是一个很小的程序,也是不可能的。
 
但是代码和路径覆盖是单元测试可达到的一个目标。事实上,单元测试阶段是把完整覆盖代码和路径作为一个合理的目标的唯一时间。
 
-          代码覆盖
在单元测试过程中,要求代码的每一行都被执行到,这一点都不过分(并且有很多分析工具可以帮助我们确保这点)。一些代码(尤其是错误处理)是不能被测试到的,除非采用额外的步骤(例如编写一个传递坏数据的函数,或者把错误代码注入到内存中),但是这些不仅仅是适合做的,而且对于确保程序可以处理各种应该处理的情况来说非常关键的!
 
-          路径覆盖
除了代码行覆盖,测试代码的每一个路径也是非常合理的。例如,我们可以确保每一个“if”的分支都经过了,并且确保每一个“case”的所有分支都得到了执行。我们还可以确保每一个循环路径的初始化和终止条件都是正确的。
 
回归测试
这些都是“新鲜出炉”的代码应该测试的内容,但是如果改变了一点点的代码模块应该做多少测试呢?在单元级别,应该做多少回归测试呢?这是很容易误解的地方:因为只是很小的改变,所以不值得花费很多的时间去测试它。
 
确实,对于每次一小行的代码的改变我们不能进行完整的测试。但是,同时,这些“很小”的改动通常带来潜在的、重大的、非预期的影响。最好的方法是恰当地评估回归测试:结合基于风险的测试和区域影响测试。
 
基于风险的测试
基于风险的测试指基于缺陷的风险来选择测试。对于风险有两个方面:可能性和影响程度。
 
可能性是判断更改会造成某些问题的机会。我们应该测试那些可能出现问题的地方。评估代码改变的地方是其中一个判断的方式,另外一个是寻找曾经出现的类似改变。
 
影响程度是关于程序出现错误时造成的损失程度(不管出现的可能性)。那些高影响程度的地方应该被重现测试。例如,程序经常被使用到的核心功能、影响安全的地方。
 
区域影响测试
区域影响测试是指专注于发生改变的代码区域的测试。例如:
 
-          一个开发人员应该完全覆盖测试增加的或改变的代码模块。
-          相应地,他应该测试所有受改变影响的路径。
-          并且,开发人员应该对那些与所修改的代码关联的地方做一些相对没有那么严格的测试。例如,如果代码改变的是参数的集合,那么应该测试那些参数被用到的地方。
 
单元测试的客观证据
计划所有这些测试都是好的,但是也需要一些客观的方式来验证测试被真正执行了。应该收集和保存什么证据来表明开发人员已经执行了那些测试?并且测试得到期待的结果?我们如何知道所有我们决定要做的这些测试已经做了并且做对了呢?
 
很明显,我们加给开发人员的验证检查的负担应该合理,并且要考虑测试被无意忽略的风险。我们不想强加不必要的作业;我们只是想确保当开发人员说一个模块已经准备好提交了,我们都知道这意味着什么。