前言
许多软件开发和验证工程师其实并不能真正理解获得结构覆盖率的重要性。大部分人这么做只是因为这是他们行业的功能标准所要求的,而并没有真正认真对待它。
像ADAS这样的安全关键系统能够实现在没有司机的情况下运送乘客、能够让自动驾驶飞行器能够在天空中飞行、通过医疗设备维持患者的生命。人们的生命依赖于这些系统。因此,获得结构化代码覆盖率是至关重要的。接下来让我们来看看什么是结构覆盖率,以及它重要的更多原因。
什么是结构覆盖率
简而言之,结构覆盖率是为了确定系统是否经过充分测试而对已执行和记录的代码的标识。安全关键系统覆盖率的彻底性取决于安全完整性级别(SIL)、汽车工业中的ASIL和航空电子设备中常用的开发保证级别(DAL)。
所谓彻底性,指的是代码中的结构元素。在嵌入式系统中,这些通常被细分为代码语句、分支、修改的条件决策,此外还可以深入到更细的粒度级别,如目标代码或汇编语言。
语句及分支覆盖率
语句覆盖是最简单的工作,它表示程序中的每一行代码。然而,代码语句可能具有不同程度的复杂性。例如,分支语句在代码中表示if then else条件,像case或switch这样的语句被解释为分支。但是,如果您要获得分支的覆盖率,这意味着必须同时覆盖真实和错误决策路径的执行。
如果需要考虑更高的安全级别,则可能需要修改条件/决策覆盖率(MC/DC)。分支的复杂性可能会逐步递增,其中一个决策中有多个条件,而每个条件都必须独立测试。
对于覆盖率标准,这意味着决策中的每个条件都已被证明能够独立地影响该决策的结果。真值表可用于帮助进行分析,如下图所示。
此外,程序中决策的每个条件都至少采用了一次所有可能的结果,程序中的每个决策至少一次采用了所有可能的结果。
在下面包含4个条件语句的示例中,有16个可能的测试用例。在本例中,MC/DC只需要5个。取条件的数量并添加1。
公式:(C + 1)
目标代码覆盖率
对于最严格的安全关键应用,如航空电子设备,流程标准DO-178B/C Level A要求目标代码覆盖率。这是由于编译器或链接器会产生额外的代码,这些代码不能直接追踪到源代码语句。因此,必须进行汇编级覆盖。
想象一下执行这项任务的严格程度和人工成本。幸运的是,有Parasoft ASMTools这样一个获得目标代码覆盖率的自动化解决方案。
(Parasoft ASMTools汇编语言代码覆盖)
获取代码覆盖率
代码覆盖率通常是通过对代码进行检测来确定的。工具化是指在用户代码中添加额外的代码,以便在执行期间确定该语句、分支或MC/CD是否已被执行。
根据嵌入式目标或设备的不同,覆盖数据可以存储在文件系统中,也可以写入内存,也可以通过串口、TCP/IP端口、USB甚至JTAG等各种通信通道发送出去。
部分插桩
值得注意的是,代码插桩会导致代码膨胀,代码大小的增加可能会影响将代码加载到内存受限的目标硬件上进行测试的能力。
其解决方法是对部分代码进行插桩。
运行您的测试并获取覆盖率。
对另一部分代码进行插桩
再次执行测试
获取覆盖率。
合并以往测试执行的覆盖率。
根据您的目标限制,理想状态是不会有太多的插桩分区要处理。不停重复运行相同的测试会非常耗时及花费成本。简单来说,插桩也许还会导致有关不良的时间和性能影响。
获得嵌入式功能及信息安全关键系统的代码覆盖率
让我们深入了解一下组织如何获得嵌入式功能及信息安全关键系统获得代码覆盖率。
对于代码覆盖率需求,比如强制的100%结构、分支和MC/DC覆盖率,有几种测试方法可以用来满足您的目标。以下为最常见的方法:
系统测试
单元测试
手动测试
结合这些不同实践的覆盖率指标是典型的。
系统测试覆盖率
通过系统测试获得代码覆盖率是确定是否执行了足够测试的最佳方法。其方法是运行所有的系统测试,然后检查代码的哪些部分没有执行。
未执行的代码意味着可能需要新的测试用例来执行可能潜伏着缺陷的未触及代码,并有助于确认以下问题:我们是否做了足够的测试?
单元测试覆盖率
如前所述,单元测试可以作为系统测试的补充方法,以获得100%的覆盖率。通过单元测试获得代码覆盖率是一种比较流行的方法,但是它并不能暴露您是否对系统进行了足够的测试,因为重点是在单元级别(函数/过程)。
这里的目标是创建一组单元测试用例,在所需的覆盖率遵从性需求(语句、分支和MC/DC)下执行整个单元,以便达到单个单元的100%覆盖率。每个单元都要重复做,直到覆盖整个代码库。然而,要充分利用单元测试,不能只关注获得代码覆盖率。这通常可以通过行路径测试用例来完成。
为了通过单元测试加速代码覆盖,Parasoft C/ C++test中存在可配置的和自动化的测试用例生成功能。可以自动生成测试用例来测试空指针、最小-中-最大值范围、边界值的使用等。这种自动化可以让您走得更远,在几分钟内,您将获得大量的代码覆盖率。
然而,与系统测试一样,由于使用了防御性代码或形式语言语义,获得100%的代码覆盖率是难以实现的。在单元的粒度级别上,防御代码可能以交换机中的默认语句的形式出现。如果捕获了交换机中所有可能的情况,则会导致无法访问默认语句。在下面的例子中,返回0;将永远不会被执行,因为while(1)是无限的。
用户可以使用调试器对语句进行标记或标记,修改调用堆栈并执行返回0;声明。视觉上见证执行过程,至少记录文件名、代码行和代码语句。
通过手动/可视化检查执行的覆盖率和报告可以用来补充通过单元测试捕获的覆盖率。两个覆盖率报告的添加可以用来证明100%的结构代码覆盖率。
(Parasoft DTP仪表板代码覆盖报告示例)
总结
结构代码覆盖率可以帮助回答以下问题:我是否进行了足够的测试?
它也可能是您必须满足的遵从性需求。获得代码覆盖率的目标是帮助我们确保代码功能安全、信息安全和可靠性的一种附加手段。它显示已执行测试的证据。通过该测试我们能够识别和修复缺陷。
您可能需要执行不同级别的覆盖(语句、分支、MC/DC等覆盖率),其中所用标准是基于您的SIL、ASIL或DAL级别。幸运的是,Parasoft提供了自动化软件测试解决方案和为了获得100%的结构代码覆盖率而所需的解决方法。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !