安全相关的软件测试方法

2020-11-18 11:39:30·  来源:莎益博工程系统开发(上海)有限公司  作者:王顺良  
 
在汽车、航空等安全相关的领域,不仅代码的体量越来越大,安全性监管也不断提高,比如汽车行业出台了ISO26262标准,航空业有DO-178标准等,对软件设计、测试和验证提出了全面、严格而且具体的要求。而企业的生存压力要求新产品尽快投入市场,这无形中挤压了设备的设计和测试周期。基于模型的设计(MBD)正是在这种情况下出现的新方法,不仅加快了系统的开发,降低了维护成本,同时对测试手段,提出了新的要求。
在汽车、航空等安全相关的领域,不仅代码的体量越来越大,安全性监管也不断提高,比如汽车行业出台了ISO26262标准,航空业有DO-178标准等,对软件设计、测试和验证提出了全面、严格而且具体的要求。而企业的生存压力要求新产品尽快投入市场,这无形中挤压了设备的设计和测试周期。基于模型的设计(MBD)正是在这种情况下出现的新方法,不仅加快了系统的开发,降低了维护成本,同时对测试手段,提出了新的要求。

软件的测试,一般可以分为静态测试和动态测试。静态测试不运行程序,根据软件的语句发现软件在合规方面的缺陷,比如MISRA C对软件的编写,对语句的使用给出了非常具体的要求。静态测试也可以根据软件的逻辑关系,发现软件可能存在的缺陷。动态测试是在软件编译完成后,利用测试用例来运行软件,以达到测试目的。动态测试能够直接考察软件行为,判断运行结果是否符合设计要求。动态测试是软件发布前最后的保障,其重要性不言而喻。

本文以汽车巡航系统为例,探讨动态测试的方法。使用的模型如下图_1和图_2所示。

图_1 巡航系统的仿真测试环境


图_2 巡航系统控制器的Simulink模型

功能测试
软件的设计是基于设计要求的,即软件所需要实现的功能。所以软件测试必须验证软件的输入输出等行为满足设计要求的功能。对于一个控制系统,手工生成测试用例的难点是,设计要求所描述的状态或场景,通常同时包含输入和输出,而且跟时序状态有关。所以在自动化测试工具出现前,系统测试需要经验丰富的工程师手动生成测试用例。

这是一个比较典型的设计要求:
      在车速小于30km/h时,巡航系统应保持不工作状态。
这是相对比较简单的测试,要求测试工程师设计用例,寻找下面表达式的反例:
      巡航系统已打开 同时 巡航系统在工作状态 同时 车辆的速度小于30km/h

而下面的功能需要系统在连续的3个时序上满足特定的状态:
      当巡航系统在工作状态,不能有连续3个时序,车辆速度和设定速度相差大于1mph。
这种在多个连续时序上满足特定状态的测试,有时候只需要复制满足条件的第一个测试用例就能实现,而有时候并不这样乐观。

在上述两种测试要求中,都用到了“巡航系统在工作状态”,从图_1可以看到,这个状态是系统的输出量,这就要求手工用例设计工程师,能够从输出量反推出一个或一组输入(测试用例),来满足“巡航系统在工作状态”这样的要求。

随着系统越来越复杂,手工反推测试用例越来越困难。我们使用美国Reactive-Systems公司的Reactis产品,自动生成测试用例,取得了不错的效果。

Reactis的验证功能,使用User-Defined-Target(UDT)和Assertion(断言)两个模块来实现。
- UDT用来自动产生测试用例,使被测系统处于设计要求的场景或状态下。
- Assertion用来发现违反设计要求的测试用例。

我们用上面提到的两条设计要求为例,看看Reactis是如何实现自动测试的。

如果车速小于30km/h,巡航系统应保持不工作状态。
对于比较简单的设计要求,Reactis支持C语言来编写UDT和Assertion。如下图_3所示进入UDT和Assertion的设置界面。

图_3 UDT的设置

从图中expression栏目可以看到,UDT的设置就是一句标准的C代码语句。对应的Assertion只需将expression替换成:
      !((speed < 30) && active)

设定完成后,软件界面上就会出现类似于瞄准镜(UDT)和闪电(Assertion)的符号(如图_7所示)。

当巡航系统在工作状态,不能有连续3个时序,车辆速度和设定速度相差大于1mph。
对于比较复杂的功能,Reactis支持Simulink/Stateflow模型来定义UDT和Assertion。如图_4所示。

图_4 使用模型的UDT设定

图_4的Library用于选择一个包含UDT模型的Simulink文件,而System在这个文件中,选择用于该测试的模型。下面的Inputs是做输入关联的,使验证模型和被测模型的输入一一对应。

Assertion的设定类似,图_5是Assertion的Stateflow模型,用于计数有几个连续时序发生速度偏差大于1mph,当发现有超过3个时序时报错。在设定完成后,软件界面上会出现带框的瞄准镜和闪电图标(如图_7所示)。

图_5 Assertion模型

测试工程师完成上述设置后,就可以利用Reactis来自动生成测试用例,如图_6所示。

图_6 自动生成测试用例的设定
由于这里只考虑UDT和Assertion,可以只选择这两项

Reactis仿照ISO26262的覆盖度测试方法,把UDT和Assertion都看作是覆盖度目标。UDT是否覆盖表示设计要求的场景或状态的测试用例是否存在,而Assertion是否覆盖表示在设计要求的场景或状态下,违犯设计要求的反例是否找到。

在生成测试用例后,会报告是否找到违反设计要求(Assertion)的情况。这时需要注意,只有在UDT实现覆盖,即找到满足设计要求所需要的场景和状态的情况下,Assertion的报告才是有效的。测试工程师可根据Reactis所报告的,发生违反设计要求的这个测试用例,对模型进行调试,发行软件的缺陷。

图_7 Reactis报告违反设计要求的测试用例

安全测试
ISO26262标准中与软件测试相关的内容,主要定义在ISO26262-6文件中,如图_8所示。

图_8 与软件相关的ISO26262

ISO26262从三方面来定义系统的危害:
- 伤害的严重性,从S0(无伤害)到S3(危及生命)
- 暴露在危险中的可能性,从E1(几乎不可能)到E4(可能性高)
- 可控性,从C0(通常可控)到C3(几乎不可控)

将上述三方面综合起来,就可以得到ASIL安全等级,从A(安全危险最低)到D(安全危险最高)。对于系统测试的每一个方面(测试目标),ISO26262用符号表示对于不同安全等级适用性:
      “++” 表示高度推荐。
      “+” 表示推荐。
      “o” 表示不推荐或不相关。

对于测试工程师来说,ISO26262-6-9的单元测试和ISO26262-6-10集成测试是最相关的部分,图_9是我们总结的测试要点。


图_9 ISO26262-6-9和6-10的测试要点

基于设计要求的测试,在前一节已经作了简要说明,下面就9.4.5和10.4.6的要求,作进一步解释。

图_10 ISO26262-6-9.4.5单元测试要求


图_11 ISO26262-6-10.4.6集成测试要求

从ISO26262-6-9.4.5可以看到,覆盖度测试,包括语句、分支和MC/DC应该在单元测试阶段得到满足。同样,ISO26262-6-10.4.6指出,函数和调用的覆盖度测试的重要性。如果未能满足这些覆盖度测试要求,应增加测试用例来满足,或说明原因。

功能测试是ISO26262的组成部分,但功能测试只是包含了设计要求所例举的一些场景,与9.4.5和10.4.6所要求的覆盖度测试,侧重点不同。功能测试所生成的测试用例,通常达不到覆盖度测试的要求。而覆盖度测试并不关心系统功能,不能验证系统是否满足设计要求。

为了进行覆盖度测试,我们依然选择美国Reactive-Systems公司的Reactis软件。行业内也有不少其他软件可以实现同样的功能,我们认为Reactis的操作比较直观,功能完整(支持基于S-Function的C代码白盒子测试),自动生成的测试用例效率比较高,并集成了调试功能。

使用Reactis实现覆盖度测试非常方便直接:
- 加载被测模型
- 定义输入变量的取值范围
- 如果需要对S-Function的C代码进行白盒子测试,只需右键点击S-Function模块,设置所包含的C代码源文件。
- 对于不需要考虑覆盖度的节点,比如S-Function的封装代码等,设置不需要覆盖。
- 钩选ISO26262-6-9和6-10所要求的测试目标,及其它关心的目标。
- 点击生成。

从图_6可以看到,Reactis提供了多种覆盖度目标,不仅包含ISO26262-6-9和6-10所要求的语句、分支、MC/DC、函数,以及调用等目标,还包括一些用户可能关心的目标。比如“CSEPT”用来对Stateflow进行测试,当主状态切换时,考察子状态是否退出。

使用Reactis的报告功能,可以很方便的查看各测试目标的覆盖度和总体覆盖度。如图_12所示。

图_12 测试用例的覆盖度报告

提高覆盖度
虽然借助测试工具软件可以自动产生测试用例,但是完全依赖工具达到ISO26262要求的覆盖度也不太可能,或者需要一些技巧。所以,如何提高覆盖度,就成为测试工程师新的课题。

从本文的功能测试部分可以看到,Reactis把功能测试也看作覆盖度目标来自动生成测试用例,可谓一切皆覆盖。所以,Reactis在提高覆盖度方面,提供了一些实用的手段。

输入量取值范围的精确设定
由于软件中包含大量的条件判断语句,这些语句对输入量的取值非常敏感,过于宽松的输入值范围,将使得自动搜寻测试用例变得非常困难,而不恰当的输入值设定,会使得搜索算法根本找不到能够覆盖的用例。所以,测试工程师在导入模型后,必须对每一个变量,根据实际的可能性进行设定。图_13是Reactis提供的输入值设定窗口,可以看到Reactis提供了丰富的设定方式,满足各种类型的取值需求。


图_13 输入取值范围的设定

利用已知测试用例
在很多情况下,我们已经有了一个测试用例的子集,比如实现功能测试的用例,我们希望扩充这个子集,来覆盖ISO26262的安全性测试要求。如图_14所示,Reactis提供了“Preload Files”功能,让用户将这个子集预先导入到软件中,当自动生成的测试用例跟子集中的测试用例重复时,可以使用“Prune”选项告诉Reactis是否可以剪切子集中的测试用例。


图_14 自动生成测试用例

聚焦覆盖度目标
当已有测试用例在某个或某些目标的测试方面表现不佳时,可以针对这些覆盖度目标进行测试用例的生成。如图_14所示,在“Coverage Objectives”栏目,可以仅仅选择需要聚焦的覆盖度目标。

使用UDT来实现覆盖
在本文的功能测试部分已经提到UDT测试。在那里,UDT主要是为了寻找设计要求的场景或状态,一般与Assertion配合使用。事实上UDT也可以单独用于覆盖度的测试。对于比较复杂的逻辑,比如涉及较长的连续时序,默认的设置很难发现有效的测试用例。这时必须明确告诉工具软件去关注这种需求。在这种情况下,就可以使用UDT来达到自动生成测试用例的目的。

结语
安全相关的控制系统测试,不仅需要满足功能验证的要求,还需要满足行业的安全规范。由于测试的要求,不仅涉及输入量,还需要同时考虑输出量、系统状态、时序、以及覆盖目标,给测试工程师提出了很高的挑战。本文以Reactis工具为例,通过使用自动化测试工具,工程师只需要从设计要求和安全要求出发,编制测试模型或测试条件,就能让工具自动产生高效的测试用例,满足功能和安全性的测试要求。 
分享到:
 
反对 0 举报 0 收藏 0 评论 0
沪ICP备11026620号