左泽轩+薛战东
【摘 要】随着民用飞机机载软件的应用越来越广泛,软件复杂程度越来越高,按照DO-178设计保证指南进行机载软件开发逐渐成为行业规范。机载软件测试是验证过程的关键,对测试结果的覆盖分析中的结构覆盖,DO-178仅提出了相关目标的抽象要求,在工程实际验证软件过程中不便理解和实现。本文结合适机载软件工程实践,浅析对测试覆盖分析过程的理解。
【关键词】DO-178 机载软件 结构覆盖 MC/DC
【Abstract】With the wider use of airborne software on civil airplane, and its higher complicity, it is gradually becoming a common standard to develop the airborne software according to DO-178 design guidance. Airborne software test is the key method of verification process. But for structural coverage, which is a step of test coverage analysis, only general requirements has been claimed in DO-178, which leads to the inconvenience of understanding and realization for software verification in engineering. In this essay, combined with experience from both suppliers management and communication with airworthiness certification side, test coverage analysis process is explained from engineering side.
【Key words】DO-178; Airborne Software; Structural Coverage; MC/DC
0 引言
随着电子信息技术的发展,机载电子设备和机载软件在民用运输飞机上的应用越来越广泛。几乎所有的航空电子系统均由软件实现其功能,并保证系统和飞机的运行安全。机载软件的质量直接影响飞机运行安全,也是飞机试验、试飞以及合格取证的保证。
相比于普通商用软件,机载软件对安全性可靠性有更高的要求,而随着复杂程度的不断提高,几乎无法通过简单的穷举测试方法保证机载软件可靠性。FAA、EASA和CAAC相继通过咨询通告,推荐DO-178B作为可接受的机载软件符合性方法,2011年RTCA最新发布了DO-178C。DO-178是基于过程控制对机载软件进行管理,但是目前国内对此还处于解读和理解阶段,按DO-178B/C进行机载软件,尤其是对应最高安全等级的A级软件研发,并通过适航审查还缺少相关经验。
在机载软件开发中,验证活动是贯穿软件生命周期的整体过程,而软件测试是验证的关键。软件测试的结果,通常还需采用测试覆盖分析进行验证。测试覆盖分析包括需求覆盖分析和结构覆盖分析。需求覆盖对应基于需求的软件测试过程,保证高级别和低级别需求被覆盖。对于结构测试覆盖,DO-178B/C中仅笼统地提出了相关目标和指南性描述,并未具体说明测试覆盖的分析方法。实际上无论是对于飞机主制造商的管理,还是国内机载软件开发商的软件验证活动,测试覆盖都是一个较难解决的问题。本文从民用飞机主制造商角度出发,根据对国外成熟机载软件供应商的管控,以及与审查方机载软件代表的沟通经验,分析结构覆盖的含义、实现和注意点。
1 测试覆盖
测试覆盖是指测试用例相对某个特定的覆盖准则而言的覆盖情况,是用来度量测试完整性的手段。覆盖率是指至少被覆盖一次的测试对象数量占测试对象总数的比例。覆盖分析主要评估软件测试用例及其测试活动的完备性,间接地可用来评估软件需求的完整性,从而保证机载软件测试活动达到相应等级的适航要求。
在DO-178B/C中,测试覆盖分析包括基于需求的测试覆盖和结构覆盖。需求测试覆盖用于分析测试用例与软件需求的追溯性,保证测试用例满足特定准则。结构覆盖用来保证基于需求的测试过程对软件代码结构的执行满足合适的覆盖要求。DO-178对不同等级软件具有不同的结构覆盖要求:D级别没有要求,C级别要求实现语句覆盖,B级别要求判定覆盖,A级别则必须满足MC/DC(修正条件判定)覆盖。
2 结构覆盖
结构覆盖是针对软件代码的覆盖分析,包括源代码、目标码和可执行代码。DO-178B/C对于基于需求的测试用例可能无法完全执行代码结构,如程序接口部分的代码,要求进行结构覆盖分析和其他额外的验证活动来保证结构覆盖率。结构覆盖可以发现在测试中未被执行到的代码结构:
2.1 语句覆盖
语句覆盖(Statement Coverage)是最基本的结构覆盖要求,要求设计足够的测试用例,使得程序中每条语句至少被执行一次,即目标是对每一条可执行语句进行覆盖测试。分析如下的程序语句:
为便于分析,将该段代码用流程图表示如图1所示,并用小写字母标注程序执行路径。
对于语句覆盖测试,为了使得代码中每条语句被至少执行一次。假设在代码的路径(b)中删除C=1的执行语句,则语句覆盖应执行流程图中两条路径。设计两条测试用例,如表1所示。
语句覆盖测试可以直接从源代码得到测试用例,无需细分每条判定表达式。但是,语句覆盖无法测试隐藏的条件和可能到达的隐式逻辑表达式。例如程序中的IF语句,若未给出ELSE语句后的执行分支,则语句覆盖会忽略该情况的测试(例如本例中不考虑A>1的ELSE条件执行语句时,依旧满足语句覆盖条件),但实际中无法排除这种分支不会被执行;或者判定中某条件错误也无法通过语句覆盖检查出来,由此可能导致代码中错误的存在。因此语句覆盖是一种很弱的、不充分的测试覆盖。
2.2 判定覆盖
判定覆盖(Decision Coverage)又称分支覆盖,要求足够的测试用例,使得程序中每个判定至少有一次为真值,一次为假值,即每个分支至少执行一次,真假各一次。因此满足判定覆盖一定能够满足语句覆盖条件。对于图1中的代码程序,设计如表2的测试用例。
表2 判定覆盖测试用例
判定覆盖的测试用例多于语句覆盖,测试能力更强,同时也无需细分每个判定中的条件。由于判定覆盖要求对分支的真假值各需执行一次,因此即使ELSE语句后没有执行语句,覆盖也要求设计相应的测试用例,从而提高了代码测试的充分性。但是,对于判定中由条件组成的布尔表达式,若仅判断最终结果而忽略每个条件的取值,可能无法发现判定条件本身的错误。
2.3 条件覆盖
条件覆盖(Condition Coverage)不作为DO-178B/C中对软件的覆盖要求。条件覆盖应包含足够的测试用例,使得判定中的每个条件获得各种可能的结果,即每个条件至少有一次为真值,一次为假值。
为了实现条件覆盖,需要设计大量的测试用例,相比判定覆盖增加了测试路径,但是并不能保证判定覆盖,因为条件覆盖只保证每个条件至少一次为真,而不考虑所有的判定结果。
2.4 MC/DC(修正判定条件)覆盖
在DO-178B/C中,条件(Condition)是指不含布尔操作符(与、或、非等)的布尔表达式;判定是指由条件,加上布尔操作符(零或多个)组成的布尔表达式。根据FAA和NASA相关资料的解释,MC/DC覆盖要求在一个程序中每一种输入输出至少出现一次,在程序中的每一个条件必须产生所有可能的输出结果至少一次,并且每个判定中每个条件必须能够独立地影响一个判定的输出,即在其他条件不变的前提下仅改变这个条件的值,而使判定结果改变。
MC/DC首先要求实现条件覆盖和判定覆盖,在此基础上对于每一个条件C,要求存在符合以下条件的两次计算:a)条件C所在判定内的所有条件,除条件C外,其他条件的取值完全相同;b)条件C的取值相反;c)判定的计算结果相反。MC/DC覆盖是条件组合覆盖的子集。条件组合覆盖要求覆盖判定中所有条件取值的所有可能组合,需要大量的测试用例,实用性较差。而MC/DC具有条件组合覆盖的优势,同时大幅减少了测试用例数。
假设对以下的代码进行MC/DC覆盖测试用例设计,并建立真值表,如表3所示。
根据表3,选取其中的一对测试用例,使得某个条件能独立影响判定的结果:选择真值对3和5,其中条件A的取值变化能够独立影响输出。继续选择新的测试用例,使得某个新的条件能够独立影响输出结果,并重复直到所有的条件都能够独立影响判定结果:对于真值对5和8,条件C的变化独立影响判定,对于真值对8和7,条件B的变化独立影响判定。如表4所示为选定的MC/DC覆盖测试用例。
可以看出,MC/DC覆盖是条件组合覆盖的子集,条件组合覆盖要求覆盖判定中所有条件取值的所有可能组合,随着条件数增加用例数呈指数增长;而理论上满足MC/DC覆盖的测试用例数下限为条件数+1,上限为条件数的两倍,因此在判定中包含大量条件时可以大大提高软件测试效率。通过MC/DC测试覆盖分析,一方面可以发现未被执行的代码,另一方面能够检查出软件中存在的问题,例如逻辑中“与”被误写成“或”,一个变量或表达式被误写成了它的“非”。
设计独立影响结果的最小测试用例集一般有两种方法:唯一原因法(Unique-Cause)和屏蔽法(Masking)。在唯一原因法中,仅关注条件值和判定表达式结果,其他所有的可能条件必须保持固定,如上分析的测试用例。屏蔽法是指对一个逻辑操作符的特定输入能隐藏对该操作符的其他输入的影响。例如对OR操作符的“T”输入可以屏蔽其他所有输入,对AND操作符的“F”输入可以屏蔽其他所有输入,只要对判定的内部逻辑分析表明关注的条件是唯一影响判定输出值的条件,那么屏蔽法允许独立影响对中多于一个输入值的变化。
对于本例使用屏蔽法分析,设X=(B and C),则判定条件可改写为(^A) or X。为了表明条件A的独立影响,X必须为“F”,否则判定结果总是“T”。此时允许B和C的值变化,只要X为“F”,因此屏蔽法产生了更多的独立影响对。通过建立中间变量来替代所有不关心的变量,也是检查条件屏蔽的有效方法。
唯一原因法和屏蔽法都可以保证判定中所有条件的独立性影响。在多数情况下,屏蔽法比唯一原因法允许更多的独立影响对,因为满足后者的测试用例组必然符合前者的要求。屏蔽法需要分析判定表达式中的内部逻辑,因此增加了一定的测试工作量。屏蔽法适用于具有耦合条件的判定中,而唯一原因法则不适用。
DO-178中对于结构测试覆盖的目标差异是不同等级机载软件的显著特征之一,尤其是针对A级和B级软件的开发成本考虑,很大程度上来源于MC/DC覆盖相比判定覆盖需要增加大量测试用例而导致的成本上升。
2.5 结构覆盖的实现
结构覆盖分析测试一般要求在源代码上进行,DO-178B/C中同时也提到了可以在中间代码或目标代码上进行。如果能够证明源代码、中间代码以及目标代码的一致性,则在这三个层面进行的分析都具有同等效力。对于A级别软件,如果目标代码中被编译环境等自动加入一些附加代码,则必须开展一致性分析。
对于不同等级软件的结构覆盖要求,通过人工构造测试用例时,需要分析每个条件对输出结果的影响,容易出现考虑不周或重复,并增加整个软件生命周期的开发成本。目前,许多商用的自动化软件工具都可以提供结构覆盖率的度量方法,如Cantata++,LDRA Testbed,VectorCAST等。它们可以搭建软件单元测试环境并进行代码覆盖率分析。通过工具软件对目标代码模块进行插桩,然后通过工具软件上传到宿主机上的历史记录文件进行分析,获得覆盖率的测试报告。
对于结构覆盖测试中发现的未执行代码结构,可能原因如下:
a)基于需求测试的用例或程序的缺失,应增加用例或程序来提高覆盖率,必要时对基于需求的覆盖率分析方法进行评审。
b)软件需求不足时,更改需求并增加测试用例和程序。
c)多余码(死代码)情况,删除并分析其影响和重新验证的必要性。若多余码出现在源代码或目标码层级,当可以表明可执行代码中不存在多余码的情况下可以允许保留(DO-178C修订的要求,在DO-178B中要求直接删除死代码)。d)未激活代码情况,结合分析和测试来表明已采用了某种手段,能防止、隔离或消除因疏忽而不当运行该类代码。
3 结束语
本文从DO-178B/C中对机载软件测试覆盖的要求出发,介绍了针对软件代码层级的结构覆盖,通过实例分别介绍了满足C/B/A级别软件的语句覆盖、判定覆盖、MC/DC覆盖概念,并说明了在工程中对于结构覆盖的实现方法。本文作为对DO-178B/C的技术性研读,能在一定程度上提高对软件测试覆盖的理解,指导机载软件的开发、验证过程。
【参考文献】
[1]王红园,郭永飞,姬琪.面向需求覆盖的航天软件测试用例优化方法[J].光学精密工程,2014(01).
[2]张军才,王娟,潘卫.基于DO-178B的结构覆盖分析研究[J].航空计算技术,2011,7,41(4).
[3]马金梭.基于模型的安全关键软件全覆盖测试方法的研究与实现[D].上海交通大学.2011.6/
[4]陈鑫,杨平.应用MC/DC准则时需考虑的问题及其改进方法[J].计算机工程与设计.2004.3.25(3).
[5]黄荦,丁立冬.基于LDRA TestBed的民用飞机软件结构覆盖率分析流程研究[J].航空标准化与质量,2014(4).
[6]岳海,任慧敏.基于修正条件判定覆盖的软件测试技术研究和方法应用[J]. 航天控制,2012,6,30(3).
[7]陈勇,严林芳,孙景华.民用飞机机载软件管理[M].北京:航空工业出版社,2015,78-79.
[8]蔡喁,郑征,蔡开元,王泽新,欧旭坡.机载软件适航标准DO-178B/C研究[M].上海:上海交通大学出版社,2013:70-71.
[9]中航工业成都凯天电子股份有限公司.机载设备适航工作指南[M]. 北京:航空工业出版社,2014:88-90.
[责任编辑:杨玉洁]