代码覆盖率的类型
如果您有 Embedded Coder®,Simulink® Coverage™,可以对软件在环 (SIL) 模式、处理器在环 (PIL) 模式下的模型以及受支持的自定义代码模块内的代码执行多种类型的代码覆盖率分析。
语句覆盖率
语句覆盖率测量代码运行时执行的源代码语句的数量。使用这种类型的覆盖率来确定程序中的每个语句是否至少被调用一次。
语句覆盖率的百分比用以下公式表示:
语句覆盖率 =(执行的语句数/语句总数)*100
语句覆盖率示例
此代码片段包含五条语句。为了实现 100% 的语句覆盖率,您至少需要进行一次 x 值为正的测试、一次 x 值为负的测试和一次 x 值为零的测试。
if (x > 0) printf( "x is positive" ); else if (x < 0) printf( "x is negative" ); else printf( "x is 0" );
条件覆盖率
条件覆盖率分析源代码中包含条件的语句。条件是包含关系运算符(<
、>
、<=
或 >=
)、方程运算符(!=
或 ==
)或逻辑否定运算符(!
),但不包含逻辑运算符(&&
或 ||
)的 C/C++ 布尔表达式。这种类型的覆盖率确定是否每个条件的所有可能结果都已评估至少一次。
条件覆盖率百分比用以下公式表示:
条件覆盖率 =(执行的条件结果数/条件结果总数)*100
条件覆盖率示例
在这个表达式中:
y = x<=5 || x!=7;
有两个条件:
x<=5 x!=7
为了实现 100% 的条件覆盖率,您的测试用例需要证明两种条件的 true 和 false 结果。例如,测试用例 x 等于 4
能证明两种条件均为 true 的情形,而测试用例 x 等于 7 能证明两种条件均为 false 的情形。
布尔赋值语句
代码覆盖率分析包含布尔值的赋值语句并将其作为条件报告。模型覆盖率仅分析赋值语句中的逻辑表达式,即仅包含逻辑运算符的表达式,例如逻辑 AND
(&&
) 或逻辑 OR
(||
)。这种差异可能导致模型和代码覆盖率结果之间出现差异,有时还会导致代码覆盖率分析中出现无法满足的条件结果。
例如,考虑以下语句:
bool A = true;
在代码覆盖率分析期间,Simulink Coverage 会分析此语句的条件覆盖率。该语句在每个时间步中均为 true,因此结果是您将获得此语句 50% 的条件覆盖率,因为不可能发生 false case。模型覆盖率不会分析该语句,因此也会造成模型和代码覆盖率结果之间的差异。
决策覆盖率
决策覆盖率分析源代码中代表决策的语句。决策是由条件和一个或多个逻辑 C/C++ 运算符 &&
或 ||
组成的布尔表达式。分支结构(if/else、while 和 do-while)内的条件是决策。决策覆盖率确定代码在执行期间执行的决策结果占总数的百分比。使用这种类型的覆盖率来确定代码中的所有决策(包括分支)是否都经过测试。
注意
DO-178C 合规性的决策覆盖率定义与 Simulink Coverage 定义不同。为了使决策覆盖率符合 DO-178C,在配置参数中,将不包含 && 或 || 运算符的布尔表达式的结构覆盖率等级设置为条件决策。
决策覆盖率百分比用以下公式表示:
决策覆盖率 =(执行的决策结果数/决策结果总数)*100
决策覆盖率示例
此代码片段包含三个决策:
y = x<=5 && x!=7; // decision #1 if( x > 0 ) // decision #2 printf( "decision #2 is true" ); else if( x < 0 && y ) // decision #3 printf( "decision #3 is true" ); else printf( "decisions #2 and #3 are false" );
为了实现 100% 的决策覆盖率,您的测试用例必须显示每个决策的 true 和 false 结果。
修正条件/决策覆盖率 (MCDC)
修正条件/决策覆盖率 (MCDC) 分析决策内的条件是否在执行期间独立影响决策结果。为了实现 100% MCDC,您的测试用例必须证明:
决策中的所有条件都已针对所有可能的结果进行至少一次评估。
决策中的每个条件都会独立地影响决策的结果。
MCDC 的百分比用以下公式表示:
MCDC 覆盖率 =(对影响决策结果的所有可能结果进行评估的条件数/决策中的条件总数)*100
修正条件/决策覆盖率示例
对于这个决策:
X || ( Y && Z )
以下一组测试用例提供 100% 的 MCDC 覆盖率。
X | Y | Z | |
---|---|---|---|
测试用例 #1 | 0 | 0 | 1 |
测试用例 #2 | 0 | 1 | 0 |
测试用例 #3 | 0 | 1 | 1 |
测试用例 #4 | 1 | 0 | 1 |
为了证明条件 Y
和 Z
可以独立影响决策结果,条件 X
对于这些测试用例必须为 false。如果条件 X
为 true,那么该决策就已经为 true 了。因此,条件 Y
和 Z
不会影响决策结果。
限制
对于代码覆盖率,MCDC 仅限于包含 1000 个或更少逻辑组合的表达式。如果表达式包含超过 1000 个逻辑组合,Simulink Coverage 会分析 MCDC,直到达到 1000 个逻辑组合的限制,然后显示 MCDC 分析不完整的警告。
圈复杂度
圈复杂度使用 McCabe 复杂度度量来测量代码的结构复杂度。为了计算代码的圈复杂度,代码覆盖率使用以下公式:
N 是代码中的决策数量。on 是第 n 个决策点的结果数量。代码覆盖率将每个 C/C++ 函数的复杂度数字加 1。
覆盖率示例
对于此代码片段,圈复杂度为 3:
void evalNum(int x) { if (x > 0) // decision #1 printf( "x is positive" ); else if (x < 0) // decision #2 printf( "x is negative" ); else printf( "x is 0" ); }
该代码包含一个具有两个决策点的函数。每个决策点都有两个结果。使用上面的公式,N 为 2,o1 为 2,o2 为 2。代码覆盖率使用这些决策和结果的公式并为该函数加 1。此代码片段的圈复杂度为:
c = (o1 − 1) + (o2 − 1) + 1 = (2 − 1) + (2 − 1) + 1 = 3
关系边界覆盖率
关系边界代码覆盖率检查具有关系操作的代码。关系边界代码覆盖率度量与模型覆盖率度量一致,如 关系边界覆盖率 中所述。模型中的定点值在代码覆盖率期间是整数。
函数覆盖率
函数覆盖率确定您代码的所有函数是否在仿真中都被调用。例如,如果您的代码中有十个独特的函数,则函数覆盖率会检查所有十个函数在仿真期间是否至少执行过一次。
函数调用覆盖率
函数调用覆盖率确定代码中的所有函数调用点是否都已在仿真期间执行。例如,如果您的代码中函数被调用了二十次,函数调用覆盖率就会检查在仿真期间是否已执行所有二十次函数调用。