时间就是软件开发中的一切。想想发现软件缺陷的时间。在发布后发现,这可能是一场灾难,危及人们的安全并造成数百万美元的损失。在发布之前发现,缺陷可以减少到仅仅是一个烦恼。
这就是为什么软件测试已成为开发生命周期中不可或缺的一部分。事实上,根据 Fraunhofter Esk 研究所 2012 年的一项调查,测试不仅是软件开发过程的重要部分,对于大多数嵌入式系统开发人员来说,它也是最困难的部分。
由于许多原因,测试可能很困难,但最基本的挑战之一是衡量进度。在测试期间未能使用可靠的指标跟踪进度可能会浪费时间并导致软件质量下降。试图忽略指标并以测试所有内容为目标是很诱人的,但这种方法很危险,因为软件测试有可能成为一项无止境的工作。Glennford Myers 在 1976 年的《软件可靠性:原则与实践》一书中证明了这一点,当时他表明一个 100 行的程序可以有多达 1018 条独特的路径。在现代软件开发世界中,软件可以增长到数百万行代码。这使得完全详尽的测试不可行。
此外,通常不仅仅是软件开发团队需要对测试水平感到满意。客户可能会要求提供代码经过适当测试的证据,而航空电子、汽车和医疗领域等安全关键行业的监管机构将需要证明对缺陷进行了充分检查的证据。因此,有必要定义一种衡量“充分”测试的方式,并且需要以一种可以客观衡量的方式来完成,以满足开发过程中的所有利益相关者。
对于有效的软件测试,开发人员需要解决如何衡量测试过程,如何确定多少测试足够,以及开发团队如何能够最具战略性地确保他们开发的软件应用程序已经过充分测试。
什么是代码覆盖率?
结构代码覆盖率分析是一种查看程序逻辑结构的哪些部分在测试执行期间已被执行或“覆盖”的方法。逻辑结构取决于所使用的代码覆盖率指标。例如,“入口点”覆盖查看在测试中执行了哪些函数调用或“入口点”。同样,“动态数据流”覆盖查看数据流的哪些部分已被执行。虽然不同的结构覆盖率指标从不同的角度检查代码,但它们都有一个共同的目的,即通过显示测试了多少代码以及执行了代码的哪些部分来对测试过程提供有意义的洞察。
专门的结构覆盖度量可以为特殊的测试用例提供服务,例如分析数据和控制耦合。但是,为了衡量一般测试的有效性,三个代码覆盖率指标已在行业中得到广泛使用:
语句覆盖率 (SC) –已执行程序的多少语句
决策覆盖率 (DC) –已执行了多少个决策分支;这实际上是语句覆盖的超集,因为要覆盖所有决策的所有分支,还必须覆盖所有语句
修改的条件/决策覆盖(MC/DC)——这建立在决策覆盖的基础上,确保复杂决策的每个子条件在其真假状态下独立执行
这些指标已被广泛认为是衡量测试彻底性的方法。特别是,汽车、航空电子和工业软件等行业已经在其软件安全标准中采用了这些指标。
更高的关键性需要更彻底的测试
值得注意的是,这些软件安全标准并未强制要求在所有项目中统一使用声明、决策和 MC/DC 覆盖率。相反,每个主要的行业软件安全标准都建议根据代码的关键程度使用不同级别的结构覆盖,尽管关键级别通常以特定行业的方式确定。例如,航空电子行业的软件安全标准 DO-178C 使用软件安全级别的概念,并要求对每个安全级别进行不同级别的结构覆盖分析。
IEC 61508 是一种通用工业软件安全标准,它定义了安全完整性等级 (SIL),并根据每个等级推荐了不同的结构覆盖率指标。
在所有这些标准中,可以看到一个共同的理念:代码必须“越安全”,所需测试的彻底性就越高。软件安全意味着什么的确切定义取决于特定行业的关注点、经验和监管压力,但这种将所需的更高级别的安全性与所需的更高级别的结构覆盖相匹配的一般原则在整个标准中保持不变。
测试应源于需求
软件安全标准中跨行业的另一个共同点是认为测试应该从需求中产生。软件需求应确定测试所需的输入和输出。如果他们不这样做,测试可能会成为一组并行的需求,这会导致混乱和软件错误。结构覆盖率不能取代需求作为测试的基础,因为覆盖率指标不能决定代码的行为方式——只有在执行期间可以访问(并且,考虑到调试器的能力,在执行期间可以访问可以是一个灵活的概念)。
虽然是互补的,但测试执行代码的有效性和测试需求的完整性是两件不同的事情。在结构覆盖分析中衡量的测试有效性着眼于代码的哪些部分被执行。测试完整性,有时称为“需求覆盖率”,查看代码是否已经针对所有需求的正确行为进行了测试。如果一个软件程序是根据其需求构建的,并且如果它不包含与其需求无关的代码,那么对需求的完整测试应该会导致测试有效地执行所有代码。如果有代码没有被测试执行,这可能是可以删除的代码,或者可能是缺少的需求,或者可能是测试中的缺陷。这样,
执行代码和测试需求之间的这种关系也存在于单个需求的层面上。虽然从证据收集的角度来看,有多少需求和测试了多少代码的高级总计更有趣,但更多的是在单个需求测试级别,以及该单个需求测试的结构覆盖分析,其中大多数缺陷被识别和修复。
结构覆盖分析通常被认为是实现 100% 指标的简单目标,但检查单个测试及其产生的结构覆盖至关重要。当正在执行的代码基于正在测试的需求时,尤其如此。通过检查代码的结构覆盖率,可以确定被测代码的确切行为,并将其与基于被测需求的预期行为进行比较。这种方法减少了由于环境因素或代码的其他部分补偿不正确代码而导致的误报。此外,如果存在不正确的行为,结构覆盖分析通常还可以提供对不正确行为原因的洞察。
当使用结构覆盖分析以这种详细的方式理解代码行为时,能够将结构覆盖分析结果覆盖在代码结构分析之上是至关重要的。此覆盖有助于将原始结构覆盖信息转换为对代码中正在发生的事情的有意义的理解。
在单元和系统级别设置覆盖目标
通常,结构覆盖分析目标可以在单元和系统级别设置。单元级别的结构覆盖是通过基于该单元要求的单元级别的测试来实现的。另一方面,系统级覆盖目标通常从更高级别需求的测试覆盖开始。然而,如果仅使用高级测试进行系统级覆盖分析,则覆盖中经常会出现漏洞。这些漏洞的原因可能会有所不同。在某些情况下,覆盖漏洞可能是由于编码标准要求的防御性编程实践造成的,但这些覆盖漏洞也可能基于从需求中实现的重要功能。
特别是,当代码基于只能通过难以或不可能在高级别上创建的条件进行测试的需求时,可能会出现结构覆盖漏洞。这种场景的一个例子是文件系统故障的功能级检查。虽然通常可能会导致文件系统故障,但要对文件系统故障进行计时以使其在该函数的执行期间发生是非常具有挑战性的。此外,以可重复的方式为将来的回归测试执行此操作可能会更加困难。在这种情况下,可能需要使用单独检查代码的较低级别的测试。出于这个原因,在收集实现测试目标的指标时,从较高级别测试测量的结构覆盖率通常与来自较低级别测试的结构覆盖率相结合。
声明、决策或 MC/DC 覆盖率等指标并不能保证软件没有缺陷。如前所述,真正详尽的测试可能是不可能的,或者至少是不可行的。然而,结构覆盖率度量可以更好地了解代码的可靠性和对测试的更大信心。
由于结构覆盖分析通过显示测试了多少代码以及执行了代码的哪些部分来深入了解测试活动,因此它可以在系统、模块或单元级别执行,并且可以累积到测试目标。 代码覆盖率不应与基于需求的测试隔离开来。此外,除了结构覆盖分析之外,可能还需要执行一些测试。例如,测试竞争条件和整数限制边缘条件对于检测缺陷可能很有价值,但它们可能无助于您的结构覆盖目标。结构覆盖分析旨在衡量您已完成的测试并指导您的测试计划,但不应将其视为目标。
谨防!
在不了解测试的情况下积累结构覆盖可能会提供一种错误的安全感,这比不充分的测试更危险。结构覆盖分析不是灵丹妙药,而是需要智能和谨慎使用的工具。但是,如果使用得当,它是一种工具,可以使测试更有用、更有效,并为测试过程提供证据。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !