当谈到汽车行业的单元测试时,大多数人首先想到的测试场景就是功能测试。功能测试即是获取属于某个单元的所有需求并编写测试用例来验证单元是否按预期功能工作。
功能测试用例
功能测试用例来源于需求,一个测试用例代表了被测系统一次“良好的运行”,覆盖了单元功能的某一方面。为了验证预期行为,测试人员通过定义特定的输入来激励被测系统,然后比较预期结果和模型或代码的仿真实际结果是否一致。由此,测试用例是将需求文本转换为可用于仿真的数据流。
由于其特性,测试用例可以写得很长来涵盖特定的行为,并且需求通常只是描述相关的输出信号以及中间观测信号的预期行为。此外,即使需求描述了输出信号的预期行为,它也可能只是提供整个测试用例中的即时信息。而不相关的信号通常被视为“Don’t care”,并且也没有定义其即时信息。
一条需求关联的所有测试用例一旦都被成功地执行了,这条需求就可认为被测试到了。尽管现在市场上有很多新的测试技术,但是功能测试是验证被测系统功能行为的标准测试方法。
结构测试用例
现在有一些工具可以自动生成测试用例,主要可以分为两类,一是随机测试用例生成,其中测试用例是通过随机选择输入数据来生成的,然后再检查达到的覆盖率。这种方法的优点是能快速地生成测试用例,但是生成的测试用例是不完整的,并且测试用例的长度可能是非常长,很难进行调试。基本上所有相关测试工具都提供了这种方法。另一类是基于Model-Checking的测试用例生成。这种智能方法生成的测试用例是完整的,而且尽可能生成最短的测试用例去覆盖某个覆盖目标,甚至可以证明某个覆盖目标永远无法达到。所以它比随机测试用例生成花费时间长一些。目前只有很少的工具能提供这种高级智能方法。
那么您可能会问,这会取代手工创建测试用例的过程吗?
粗略的答案是:不会!
完整的答案是:视情况而定!
如果有机器可读的需求即形式化需求,那么Model-Checking技术就能生成功能测试用例。具体信息请查看BTC EmbeddedSpecifier
假设我们现在没有机器可读的形式化需求,那些自动生成的结构测试用例如果不是来替换功能测试,那么它们的目的是什么呢?
什么是结构测试用例?
对于功能测试,需求是测试用例的信息来源,即便对于形式化需求也是如此,这点与自动生成的结构测试用例类似,但信息来源却不同。
这些工具不考虑需求,而是将被测试系统的结构属性作为测试用例生成的来源。自动生成的测试用例可以考虑许多可能的结构特性。基本上,它们都是关于模型或代码覆盖率的。最常见的覆盖目标是语句、分支或决策、条件和修改的决策/条件覆盖(MC/DC),其中ISO26262中在软件单元层级提出的结构覆盖目标如下图所示
还有很多类似于函数覆盖、等价类或单独指定的覆盖目标,如下图所示为ISO26262中在软件架构层级提出的结构覆盖目标
为了避免误解,这类测试用例就被称为结构测试用例,当然它们的特性也有所不同。它们不是验证需求,而是通过改变输入和标定参数来“应激”被测系统。通常,这些测试用例很短,它们考虑了所有步中的所有信号,没有“Don’t care”的信号。
但是,如果这些测试用例来自于被测系统,然后又在被测系统上执行,这难道不是一个自我实现的预言吗?
激励向量生成
推导结构测试用例可以分为两步。首先,(我们称之为)引擎生成激励向量。激励向量只包含输入数据,即每个输入信号和每个标定参数的数据,不包含任何关于输出和中间观测量的信息。所以这些激励向量只描述了如何达到一定的覆盖目标。
因此,通常激励向量是来自模型还是来自代码并不重要。如果我们深入研究这个话题,那么将代码作为源头有几个很好的理由,但是要注意的是如果使用一般的方法,由模型还是由代码推导出激励向量并没有什么区别。
这些生成的激励向量的首要好处就是,它们可能已经指出了模型或代码中的一些结构性问题,这些问题与被测系统的鲁棒性有关,比如溢出、除零、值超出范围或无效值等。
背靠背等效性
第二步是要从激励向量派生出结构测试用例。由测试人员决定,应该从哪个源实现派生出输出行为。在基于模型的开发中,这通常是模型。因此,所有生成的激励向量都在模型上执行,并记录仿真的输出。这样激励部分和记录的仿真输出行为一起构成了一个结构测试用例。
结构测试用例的使用场景
- 模型和代码或目标代码之间的背靠背等效性测试
- 新旧版模型、代码或目标代码之间的回归测试
- 迁移到新的开发环境
- 新旧处理器之间的比较
现在可以在代码上再次执行这些结构测试用例,以验证代码的结构行为是否与模型相同。换句话说,它验证模型是否正确地转换为代码。最常见的问题比如精度误差、数据溢出甚至编译器差异等,这些都可能导致模型和代码之间的行为不同。因此,ISO 26262强烈推荐进行背靠背测试。
由于这种方法依赖于模型或代码以及所选的覆盖率目标,所以它不需要来自测试人员的额外输入或交互。因此,这种测试方法可以完全自动化,并可应用于开发和测试过程的持续集成环境中去。
结构测试用例并不是为了…
自动生成结构测试用例是一种很方便的方法,但这也引出了一个问题,是否生成的测试用例能随机地符合一条需求。即使这在理论上是可能的并且有白皮书在理论上讨论过这种方法,但几乎绝对肯定不可能这样做。
但是让我们暂时假设一些生成的结构测试用例符合需求。这意味着测试人员必须手动检查所有生成的测试用例,并检查其中一个是否符合需求中的一条。由于模型或代码仍然可能包含错误,因此这种方法可能无法发现功能上的错误。
此外,随着需求的增加和生成的结构测试用例的增加,该任务的工作量和复杂性将明显成倍地增加。一旦完成了这一步,测试人员仍然必须为尚未覆盖的需求编写额外的功能测试用例。最后从工作和复杂性的角度来看,这种方法并不适用于实际的测试工作流。
总结
尽管自动生成的结构测试用例和手工编写的功能测试用例之间有很大的区别,但是它们是功能测试的有效补充,能发现模型和代码之间的结构问题。另外,试图将自动生成的结构测试用例映射到需求并不是一个合适的方法。
功能测试用例检查功能设计是否正确且与预期是否一致。而结构测试用例则查看语法并检查它是否被正确地翻译成另一种语言。最后,将结构测试用例自动生成应用到测试工作流中,可以提高测试的深度和鲁棒性。