如果您编写程序,通常可以驱动它以覆盖所有路径。因此,很容易获得 100% 的覆盖率(忽略现代编译器无论如何都会捕获的不可行的代码路径)。
但是,100% 的代码覆盖率应该意味着所有变量定义使用覆盖率也都实现了,因为变量是在程序中定义并在程序中使用的。如果涵盖了所有代码,则还应涵盖所有 DU 对。
那么,为什么说路径覆盖更容易获得,但数据流覆盖通常不可能达到 100% 呢?我不明白为什么不呢?有什么例子呢?
如果您编写程序,通常可以驱动它以覆盖所有路径。因此,很容易获得 100% 的覆盖率(忽略现代编译器无论如何都会捕获的不可行的代码路径)。
但是,100% 的代码覆盖率应该意味着所有变量定义使用覆盖率也都实现了,因为变量是在程序中定义并在程序中使用的。如果涵盖了所有代码,则还应涵盖所有 DU 对。
那么,为什么说路径覆盖更容易获得,但数据流覆盖通常不可能达到 100% 呢?我不明白为什么不呢?有什么例子呢?
实现 100% 的代码覆盖率比所有可能的输入更容易,因为所有可能输入的集合可能非常大或实际上是无限的。 测试它们需要太多时间。
让我们看一个简单的示例函数:
double invert(double x) {
return 1.0/x;
}
单元测试可能如下所示:
double y = invert(5);
double expected = 1.0/5.0;
EXPECT_EQ( expected, y );
该测试实现了 100% 的代码覆盖率。但是,在 1.8446744e+19 个可能的输入中只有 1 个(假设双精度为 64 位宽)。
All-pairs Testing背后的想法是,测试每个可能的输入是不切实际的,因此我们必须确定涵盖所有情况的范围。
在我的invert()
函数中,至少有两组重要:{非零值}和{零}。
我们需要添加另一个测试,它涵盖相同的代码路径,但结果不同:
EXPECT_THROWS( invert(0.0) );
此外,由于测试编写者必须设计不同的可能参数集以实现对测试的完整数据输入覆盖,因此不可能知道正确的集是什么。
考虑这个函数:
double multiply(double x, double y);
我的直觉是为小数字编写测试,为大数字编写另一个测试,以测试溢出。
但是,开发人员可能写得不好,以这种方式:
double multiply(double x, double y) {
if(x==0) return 0;
return 1.0 / ( (1.0/x) * (1.0/y) );
}
如果我们的测试没有使用 0 表示 y,那么我们就会错过一个错误。了解如何设计算法对于理解单元测试的正确输入非常重要,这就是编写代码的程序员需要参与单元测试的原因。