在软考软件评测师的知识体系里,测试用例设计方法被划分为两条主线:黑盒测试与白盒测试。黑盒测试把程序当作一个打不开的盒子,只依据需求规格说明考察输入与输出之间的对应关系,典型方法包括等价类划分、边界值分析、判定表、因果图与场景法;白盒测试则打开盒子,依据程序内部的逻辑结构来设计用例,逻辑覆盖正是白盒测试用例设计技术的核心主干。
教材对逻辑覆盖的正式表述是:以程序内部的逻辑结构为基础,设计测试用例,使程序中的某些结构元素被执行或取值,从而度量并提升测试对程序结构的覆盖程度。这里的结构元素,可以是一条语句、一个判定、一个条件、一组条件的组合,也可以是一条完整的执行路径。依据所覆盖结构元素的粒度不同,逻辑覆盖自弱到强依次划分为语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖与路径覆盖六种准则。其中语句覆盖、判定覆盖、条件覆盖称为基础准则,判定条件覆盖、条件组合覆盖属于组合准则,路径覆盖是强度最高的准则。
与逻辑覆盖并列的白盒技术还有基本路径测试与循环测试。基本路径测试以环路复杂度为依据确定独立路径条数,与逻辑覆盖互为补充;循环测试专门针对循环结构的边界取值。软考命题时常将三者放在同一道题里辨析,考生必须首先把逻辑覆盖这一主干定义吃透,才谈得上后续的强弱关系判断与用例设计。
值得强调的是一组易混术语:覆盖、覆盖准则与覆盖率。覆盖是测试用例对程序结构的执行行为;覆盖准则是衡量覆盖是否达标的形式化规则;覆盖率则是满足程度的量化指标,例如语句覆盖率达到百分之百表示每条语句都至少被执行过一次。软考真题经常在题干中给出覆盖率的数字,要求考生反推测试集满足的是哪一档准则,术语的准确理解是得分前提。
从学科发展脉络看,逻辑覆盖准则源于结构测试的工业实践。二十世纪七十年代,测试界发现仅凭直觉挑选用例难以复现缺陷、难以度量工作质量,于是引入覆盖率的工程度量,让测试从经验行为转变为可管理、可审计的工程活动。此后航空软件适航标准DO-178系列又把修正条件判定覆盖写入强制条款,使逻辑覆盖上升为安全攸关领域的法规要求。理解这条脉络有助于把握命题方向:软考考的是工程度量思想,而非孤立的名词背诵。
还需澄清一个边界:逻辑覆盖的度量对象是程序的控制结构,而非数据。判定中条件的取值属于控制信息,变量参与的具体数值属于数据信息,二者职责不同。黑盒测试的边界值分析专门针对数据取值,逻辑覆盖只关心控制流向,命题人有时会把数据取值充足与结构覆盖充分混在一起设问,考生要能区分两套度量体系各自回答什么问题。
逻辑覆盖的度量基础是控制流图。控制流图把程序从语法文本抽象为有向图:节点代表基本块或语句,边代表控制转移,判定节点处产生分支。构造时有三条要点。第一,顺序执行的连续语句可以合并为一个节点,因为顺序结构中不存在分支,覆盖任何一个与覆盖全部等价。第二,判定节点是产生出边的唯一位置,条件语句与循环语句各自产生两条出边,分别对应条件成立与不成立两种情况。第三,复合判定在控制流图上只对应一个判定节点,但其内部包含多个简单条件,这正是条件覆盖与判定覆盖产生差异的根源。
一个复合判定由若干简单条件通过与、或逻辑连接而成。例如判定"A大于一并且B等于零",内部包含"A大于一"与"B等于零"两个简单条件。判定覆盖只关心整个判定取真取假两种情况是否都被执行;条件覆盖则深入到每个简单条件,要求每个条件各自取真取假至少一次。粒度不同,强度自然不同,这正是覆盖准则分级的底层逻辑。
测试充分性问题无法用穷举解决。即使一个很短的顺序程序,只要包含循环,其路径数量就可能达到天文数字,穷举全部路径在工程上不可行。逻辑覆盖的解题思路是以退为进:放弃穷举,转而定义一组有限的覆盖目标,只要测试集覆盖了全部目标,就认定测试达到相应充分性水平。语句覆盖的目标集合是所有语句,判定覆盖的目标集合是所有判定真假分支,条件覆盖的目标集合是所有简单条件的真假取值,条件组合覆盖的目标集合是所有条件取值的笛卡尔组合,路径覆盖的目标集合是所有可行路径。
各准则之间存在包含关系,学术上称为子蕴含关系。如果准则甲蕴含准则乙,那么满足甲的测试集必然同时满足乙。语句覆盖被判定覆盖蕴含,因为走到每条语句必然途经每个判定的至少一个分支;判定覆盖被条件组合覆盖蕴含,因为条件组合全部取到必然使每个判定真假都出现过。但有两处反直觉的例外:条件覆盖并不蕴含判定覆盖,条件覆盖也不蕴含语句覆盖,原因是仅保证每个简单条件取真取假,可能出现组合出的每条用例都令复合判定整体取假的情形。这一例外是软考命题人最偏爱的陷阱,后面误区一节还会展开。
控制流图还有一个容易忽略的细节:循环结构的出边。循环体在控制流图上形成一条回到判定节点的回边,判定节点的真分支进入循环体,假分支离开循环。基本路径法计算独立路径数时,回边是产生新路径的关键;逻辑覆盖度量覆盖率时,循环至少执行零次与至少执行一次的区别也要体现。不少考生画控制流图时把循环展开成若干次顺序执行,这是错误的,展开多少次都无法代表任意次迭代,图上的回边才是循环的正确表达。
从充分性理论看,逻辑覆盖六准则构成一个从弱到强的谱系,两端对应两种极端立场。语句覆盖代表最低限度立场,追求以最小成本获得形式上的覆盖证据;路径覆盖代表理想完备立场,追求穷尽一切执行可能。工程实践必然在两端之间取折中,判定条件覆盖与条件组合覆盖就是这个折中带上最常用的刻度。理解谱系的存在意义比记住每个名词的定义更重要,因为综合应用型题目考的就是在约束条件下选择合适刻度的能力。
为便于理解,本节统一使用一个经典示例程序。该程序包含两个判定:第一个判定是"A大于一且B等于零"的复合条件,成立时执行X除以A的赋值语句;第二个判定是"A等于二或X大于一"的复合条件,成立时执行X自增语句。程序共四条可执行语句、四个判定分支、四个简单条件。
语句覆盖是最弱的准则,要求设计足够的测试用例,使程序中每条可执行语句至少执行一次。取用例"A等于二、B等于零、X等于三",程序走通全部语句,语句覆盖率达到百分之百。但该用例只让第一个判定走真分支、第二个判定走真分支,四个判定分支只执行了两个,判定覆盖率仅有百分之五十。语句覆盖的问题在于对判定内部的分支结构不敏感,无法发现条件写反、分支缺失一类缺陷。
判定覆盖又称分支覆盖,要求每个判定的取真分支与取假分支至少各执行一次。对示例程序,组合用例"A等于二、B等于零、X等于三"与"A等于一、B等于零、X等于一",前者走真真路径,后者走假假路径,四个分支全部覆盖。判定覆盖蕴含语句覆盖,强度高于语句覆盖,但依然粗糙:第二个判定中"X大于一"这个简单条件的假取值从未单独出现,或逻辑中的条件错误难以被这种用例暴露。
条件覆盖要求每个判定中的每个简单条件取真值、取假值各至少一次。取用例"A等于二、B等于零、X等于一"与"A等于一、B等于一、X等于二",第一个用例令A大于一为真、B等于零为真、A等于二为真、X大于一为假;第二个用例令A大于一为假、B等于零为假、A等于二为假、X大于一为真,四个条件各自真假均取到,条件覆盖达标。但观察可知,两个用例都使第一个判定整体取真、第二个判定整体取假,判定覆盖率仍然只有一半,这就是条件覆盖不蕴含判定覆盖的实证。
判定条件覆盖是判定覆盖与条件覆盖的合取,要求测试集同时满足两条要求:每个判定的真假分支至少执行一次,每个简单条件的真假取值至少出现一次。取用例"A等于二、B等于零、X等于四"与"A等于一、B等于一、X等于一",前者走真真路径,后者走假假路径,四个判定分支齐备;同时四个简单条件的真假取值也全部出现。判定条件覆盖解决了条件覆盖不保证分支覆盖的缺陷,但它并未检查条件之间的组合关系是否充分,与逻辑中短路求值相关的缺陷仍然可能漏过。
条件组合覆盖又称多重条件覆盖,要求每个判定中条件取值的所有可能组合至少出现一次。示例程序的两个判定各含两个简单条件,每个判定有四种取值组合,两个判定共八种组合。设计用例"A等于二、B等于零、X等于四"、"A等于二、B等于一、X等于一"、"A等于一、B等于零、X等于二"、"A等于一、B等于一、X等于一",四个用例即可让八种组合全部出现。条件组合覆盖满足判定条件覆盖与判定覆盖,但它只穷尽了判定内部的组合,判定与判定之间的路径组
本篇完!