每个产品都会有缺陷,在开发过程中应争取尽早发现缺陷,开发的时候提高软件质量要远比开发完成后再进行测试更为有效。验证和确认技术可用于整个产品开发周期中,能确保所制造的是正确的产品,同时产品是在按正确的方法制造。本文介绍验证和确认基本原理和技术,并讨论如何成功地将这类技术应用于高质量嵌入式软件开发过程中。
V&V主要内容
在V&V过程中要检查很多内容,但其中四项最为重要,分别是完整性、一致性、可行性和易测性。
完整性是指一个产品与其前期设计的产品是一个完备的整体,它意味着没有标为“TBD”(待定)的项目、没有根本就不存在的参考源、也没有规范项目遗漏(特别是容易忽略的特殊情况)、功能遗漏和产品遗漏。如果以前的产品具有某种功能或特性,则被审产品对相同功能或特性也应有类似的处理方法。
一致性指产品不会提出矛盾的要求,它可以是内部的(指产品本身内部),也可以是外部的(相对于另一个产品而言)。例如一个函数定义的输出值可能会与它调用的另一个函数的输入发生冲突,各个函数本身可能都是正确的,但在产品开发中将两个函数集成到一起时,就会明显地出现问题。
可行性主要指被审产品能否完成。例如某个要求从用户的观点来看在内部可能是一致且正确的,但对于分配给该产品的人力资源水平而言却是无法达到的;与之类似,一个规范可能要求一个模块具有某种性能,但以目前的技术却根本无法实现。可行性还应考虑风险问题,不管这种风险是否与技术、费用、进度、环境还是系统与其它系统或用户之间的相互影响有关。
易测性指对产品做指定测试的能力,特别要说明的是该测试必须是具体的、明确的和可以量化的,否则就不能进行。例如,假设有一个指标表述为“分类算法应该尽可能快”,这样的要求就不能在产品中做测试,因为没有一个客观的测量方法能判定其测试是通过还是不通过。由于设计人员和编程人员必须在制造最终产品前说明这些事项,而不是在之后发现问题,所以加强对易测性的关注不仅使产品更具有可测性,而且能得到质量更高的产品(不管它是否经过测试)。另外,易测性还包括“出货标准”的确定,它能使测试工程师们知道产品在装运前经测试后所达到的质量水平。
评审会议
参加评审会议的人员一般应只限于3~5人,在这种会议中,各个成员都有明确的分工,他们事先都应经过培训。为使会议能取得成效,每个参加人员都要事前做准备,花费的时间一般不超过两个小时;另外会议的长度应适当控制,一般也不超过两个小时。这种会议使评审人员仅关注于产品的一小部分,下面是一些有用且重要的应用原则。
◆ 评审的是产品而不是它的设计者 产品设计人员不属于评审范围,但是要客观地讨论产品而不涉及与之相关的人是非常困难的。在某些极端情况下,设计人可能只是被要求作为一个读报告的人或是一个旁观者来参加会议,也可能根本就不邀请他参加会议。此外评审的结果不应拿来针对某个工程师,虽然产品中存在的缺陷可能因他而起。
◆ 设定会议议程并按之进行 如果5个工程师一起用4个小时(相当于一个人半周工作时间)来评审产品,其费用是很大的,要想使这种评审取得成效(或作为过程的一部分保留下来),所有参加者应有这样的观念,即他们的时间没有白费。
◆ 要限制争论和辩解 主持人必须对会议保持控制,如果有不同意见,可以由记录员记录下来,作为工作项目指派给合适的人员,而会议则继续下去。任何过度的(即超过最低限度的)争论和辩驳都会破坏前述设定议程并按之进行的原则。
◆ 搞清问题所在但不要试图去解决任何事情 会议的焦点是发现而不是解决,正式评审中小组的目的不是进行共同设计。激进的意见有时很吸引人,必须予以压制。会议应沿着发现问题的思路进行,具体负责工程师以后会有足够的时间进行修改。
◆ 进行记录 需要指定一个记录员,此人最好除了记录以外没有其它任务,这样会议记录才会对会后负责修改的人员有所帮助。
◆ 限止参加的人数 避免让那些只想作壁上观的旁观者参加,一个房间有一个最佳参加人数,超过这个数肯定会影响会议的效果。
◆ 要强调事先准备 为保证会议按议程安排进行,并保证所有与会者的时间都得到充分应用,每个参加者必须事先作好准备。没有预先准备,每个人的时间都会被浪费掉,因为没做准备的人实际上是在其他人面前才开始学习。一般应在会议安排日期之前的2~3天将材料分给参加者。
◆ 针对每一个要评审的工作项目制作一个检查对照表 对于评审和检测来讲对照表是绝对必要的,应按不同种类的工作项目制作专门的对照表。这种检查对照表可以用来过一遍,并对相关问题进行彻底的检查。此外随着会议进展又会出现一些其它方面的问题,因此对照表本身也应有所改进,不断变得更加彻底完整。
◆ 分配好资源和时间进度 要想评审取得效果,管理层必需明白所花费的时间价值,并做出相应安排。如果评审安排没有把与会工程师们所花的时间考虑进去,评审就不会成功,这样做体现了管理层对该项工作的信任,否则必将失败。
◆ 对所有评审人员进行有效的培训 虽然召开有效的评审会议对有些人来讲没有问题,但对所有参与者进行适当的培训还是很重要的。这种培训也许不能给参加人员灌输必要的技能,但能使所有人员了解正确的约定规则。如果参与人员没有完全懂得基本规则,即使是一群天才或十分积极热情的人也会浪费大量的时间,进行无效的评审。
◆ 对早期评审进行复审 没有什么一成不变的做法在任何环境下都可以永远适用,评审必须按用户要求进行,并随时修改以满足开发部门的要求,所以评审本身也应进行复审以便在过程中作适当的修改。
有证据表明在许多场合下检查是很经济的,关于这一点的主要原因是检查能在修复费用相对较低的早期阶段发现缺陷。此外当要求作必要的修改时,对多层次设计文件、产品代码及产品文件进行改动会出现脉动效应,而检查能防止这类效应,有效评审的另一个关键是它设计为检测缺陷而不是检测失效。最后,因为每一个中间产品必须要能追溯至前一级中间产品,所以评审必然会改善整个流程,而要求的准备和设计工作都做得很差的小组几乎就拿不出合适的东西进行评审。
虽然大家都很清楚评审能大大有助于提高软件质量,但对它还可以降低费用这一点可能就不那么直接,然而有证据表明实际上可能的确是这样。图1显示了一条“蜗形曲线”,可以解释在前期检查多花的费用如何在后期测试时间(主要为修正错误和回归测试阶段)的节约上得到回报,从而最终节约了总体费用。
那么什么地方是留给测试的呢?其实就在它原来的地方。以我们对设计和制造产品的信心而言,即使小心进行所有工作,测试也不可能像将其放在水中看它是否浮起那么简单。因为产品中必然有缺陷,所以需要按步骤运行软件。不过如果检查得到很好实施,那么测试开始时留在产品中的缺陷数将会非常少。
测试过程
虽然正式评审和检查占用了我们大量的精力,测试仍然是V&V中很有用且很重要的一个部分。测试时我们在受控状态下运行软件以检测缺陷,如同我们在提要求、设计和编码等各阶段进行评审和检查一样,我们在软件制作的任何适当的地方进行测试。下面将简单介绍单元测试、集成测试、系统测试和回归测试。
◆ 单元测试 单元测试的任务是在一个受控环境中执行一个特定模块。它一般包括某种形式的构架,通常为短线程和驱动器。短线程是一个测试软件模块,位于被测单元下方,可以模仿从属模块的行为;驱动器也是测试软件模块,位于单元的上方,并以与其调用模块相同的工作方式驱动该单元。短线程和驱动器一般协调工作以构造出测试模块必须响应的条件或状态。
单元测试一般用来验证模块的功能属性,但也可以测试其它项目,如性能、可用性等等,可使用“黑盒”或“白盒”方法进行。在“黑盒”测试中,模块被当作一个不知道内部行为的盒子,它在运行时可以观察输入值及所映射的输出值。因为这些映射是特定的,所以能够针对所产生的输出值来测试各种可能输入值或条件。建立这样的测试一般不用参考内部代码,测试的结果要末通过要末不通过。
与之相反,“白盒”测试需要了解代码(虽然同样应取决于适当规范)。例如,测试通过搜寻执行的每一行代码或者保证在每条可能的路径中都穿越了所有判定点来关注控制流,不过测试也可以关注数据流,方法是看是否已考虑了所有的数据操作。
单元测试一般看作验证的一种形式,因为它将功能模块的行为与功能规范进行比较。
◆ 集成测试 当各模块己经过单独的单元测试后,我们就将它们组合到一起,看与其它模块集成在一起时的整体功能。模块可按多种途径集成,包括从上向下和从下向上。实际上任何方法都可以使用,只要测试人员能了解特定模块组合所表示的行为,组合从最前面两个模块开始,到加入最后一个模块结束,形成一个完整的系统。理想状况下,集成测试应每加入一个模块进行一次。
集成测试一般也看作验证的一种形式,因为组合模块的行为是一个功能规范的产品
◆ 系统测试 系统测试是指对整个系统或产品进行测试,看它是否符合总体系统要求。系统测试人员相当于用户代言人,因为测试指导文件应该或者是用户提出的需求,或者是直接基于这一要求的技术规范。
系统测试可用不同的方法进行,包括模拟和真实运行。在有些系统中(如发射一架新型航天飞机)不可能对运行中的真实软件进行测试,所以要仔细创建一个构架对系统必须要响应的所有外部条件进行模拟。在这种情况下对测试模拟器的质量依赖性很大,使模拟器处在一个很微妙的两难境地。虽然同样情况也出现在任何自动系统测试中,但模拟器因为其复杂性以及缺少其它确认方法而在这方面尤其困难。
系统测试能发现任何质量问题,包括功能、性能、可靠性和可用性,但肯定还不止于此。
◆ 回归测试 回归测试就是漏洞修复完成后再对软件进行测试,以确保软件没有产生“回归”或因修复而变得更糟,这种测试一般要重新运行最初发现问题的原始测试程序。有关回归测试有两个焦点,首先最重要的是看有没有产生新的漏洞,第二点要看修复是否确实使失效己经消除。为进行有效的回归测试,自动测试一般是肯定需要的。测试可以分成慢速低效和快速高效两大类,如果使用快速高效方法,做回归测试相对来说不用费什么事。
人员要求
测试是一个专业,要用专门的一套技术来进行这些关键的V&V工作。好的测试人员从一开始就参加软件开发,可为产品开发阶段带来一种质量的观念。他们应用工程技术构建高效自动测试程序,根据需要来设计这些测试,并将之用于验证和确认。他们明白尽量使产品暴露出问题才是公司和用户的最大利益所在,他们也是工程师,其产品则是测试程序,严格来说他们的技能与那些开发工程师并不相同。尽管如此,更广泛地讲有两类人常常和测试联系在一起:用户和开发人员,但用这两类人作测试都存在一些问题。
开发人员的工作是构建,他制造产品;而测试人员的任务则是破坏,他“折磨”产品。每个工作都要求特定的个性,在两者之间随意变动不是什么小事。更重要的是,绝对不能让开发人员去测试他们自已的代码,因为当处理到自己代码里的薄弱部位时,他们会不自觉地退缩,不是很好地了解问题而是绕开软件中有问题的部分,他们没有足够的勇气对自己动手术。即使能想办法对一个开发工程师进行洗脑使他能够批判自已的代码,但和一个旁观者相比,其效果还是要差得多,在这个工程师眼里导致出现某种缺陷的盲点无疑会在对同一软件的测试中再次起作用。
另一个常用的方法是由用户来进行测试。虽然用户在可用性方面能提供大量反馈,但如果软件具有较高的质量,他们一般在功能测试方面就很弱。用户在测试时通常只是重复,不够系统,另外还缺乏想象力。由于对新软件缺乏信心,他们的速度也比较慢。前面已讲过,用户是了解潜在使用类型的最好资源,因此可以让测试人员根据实际使用模型将测试集中在可能有问题的区域。
本文总结
许多公司对独立测试或功能验证相当满意。对安全的需求是很明显的,特别在制造嵌入式系统时情况更为如此,这类系统不像其它平台那样能够非常容易地升级。但这些公司的测试一般是在流程结束时才会进行,仅仅作为为数不多的几种客观方法之一,以确定产品达到必要的质量水平。
本文的重点一直是评审和检查,尽管这两种技术提供了一个更可靠的机制,可以随着开发阶段的进行将质量制造在产品中,但它们在软件公司中使用得并不普遍。用很少人对产品进行直观检查在很多方面会相当费力,但其潜在的好处是巨大的。
每个产品都有缺陷,这是无法改变的,但产品中的缺陷迟早都是会发现的。最坏的情况是在应用现场发现,最好则是尽可能早地在软件开发过程中发现缺陷。这是一个很充分的理由应该制造缺陷更少的产品,并且这些剩下的缺陷其严重程度应能被用户所接受。当你在开发一个用于嵌入式器件的软件时,必须要保证在产品发布前它是正确的,如果到下一个版本器件推出时才发现一切可能就太晚了。