2008-10-04 140 views
2

将我当前的代码项目转换为TDD,我注意到了一些东西。“代码覆盖”与“代码测试”?

class Foo { 
    public event EventHandler Test; 

    public void SomeFunction() { 
     //snip... 
     Test(this, new EventArgs()); 
    } 
} 

当测试此代码并依靠代码覆盖率工具确定您是否有足够的测试时,可以看到两个危险。

  • 您应该测试Test事件是否被触发。只有代码覆盖工具不会告诉你,如果你忘记了这一点。
  • 我会在第二秒内找到另一个。

为此,我添加了一个事件处理程序,我的启动功能,使得它看起来是这样的:

Foo test; 
int eventCount; 

[Startup] public void Init() { 
    test = new Foo(); 
    // snip... 
    eventCount = 0; 
    test.Test += MyHandler; 
} 

void MyHandler(object sender, EventArgs e) { eventCount++; } 

现在,我可以简单地检查eventCount看到我的事件被调用多少次,如果它被称为。很简约。只有现在,我们已经通过了一个永远不会被任何测试捕获的阴险小错误:即,SomeFunction()在尝试调用它之前不检查事件是否有任何处理程序。这将导致一个空的解除引用,它将永远不会被我们的任何测试所捕获,因为它们都默认附加了一个事件处理程序。但是,代码覆盖工具仍然会报道全面覆盖。

这只是我手边的“真实世界的例子”,但即使对代码有100%的“覆盖率”,我也会发现有更多的这类错误可能会漏过,但这仍然不能解释到100%测试。在编写测试时,我们是否应该用这样一种工具报告覆盖率?是否还有其他种类的工具可以抓住这些漏洞?

回答

4

我不会说“把它当作一粒盐”(有很多实用程序代码覆盖率的),而是引用自己

TDD和代码覆盖不是 灵丹妙药:

·即使有100%的块 覆盖率,仍然会有该选择哪个 块执行条件错误 。

·即使100%块 覆盖率+ 100%弧覆盖率, 仍然是直线 代码中的错误。

·即使采用100%的块 覆盖率+ 100%弧覆盖范围+ 100% 执行 无差错换在-至少一路径 直线代码,仍有 将被输入的数据路径/循环的方式显示更多 错误。

(从here

虽然可能有一些工具,可以提供改进,我认为高阶位是代码覆盖率只是一个整体的测试策略,以确保产品质量的一部分。

+0

好帖子其实,感谢分享。 – 2008-10-04 13:23:56

2

在编写测试时,我们是否应该用这样一种工具报道覆盖率?

绝对。覆盖工具只会告诉您测试过程中代码中的哪些比例线实际上是运行。它没有说明如何彻底清除这些线。一些代码行只需要测试一次或两次,但有些需要在各种输入上进行测试。覆盖工具无法区分差异。

1

此外,如果测试驱动程序只是对结果的正确性没有有意义的断言行使代码,那么100%的测试覆盖率并不意味着太多。

+0

即使有意思的断言,仍然会出现这样的情况:您可以执行所有执行线程,完成有意义的测试,但仍然无法完全测试。例如,边界检查通常可以在一个条件下完成,但您应该单独测试欠载和超限。 – 2008-10-04 13:11:52

0

覆盖范围仅用于识别尚未经过测试的代码。它没有告诉你很多关于已经被覆盖的代码。

0

是的,这是“线路覆盖”和“路径覆盖”之间的主要区别。在实践中,您无法真正测量代码路径覆盖率。像静态编译时间检查,单元测试和静态分析 - 线覆盖只是您追求高质量代码时使用的另一种工具。

4

< 100%的代码覆盖率很差,但并不表示100%的代码覆盖率是好的。这是一个必要但不充分的条件,应该这样对待。

另外请注意,有代码覆盖和路径覆盖之间的差异:

void bar(Foo f) { 
    if (f.isGreen()) accountForGreenness(); 
    if (f.isBig()) accountForBigness(); 
    finishBar(f); 
} 

如果传递一个大的,绿富成代码,测试用例,你会得到100%的代码覆盖率。但是,对于所有你知道一个大的,红色的Foo会使系统崩溃,因为accountForBigness错误地假定某个指针是非空的,只有通过accountForGreenness使其非空。您没有100%的路径覆盖率,因为您没有覆盖跳过accountForGreenness调用的路径,但没有覆盖accountForBigness调用的路径。

也可以在没有100%路径覆盖的情况下获得100%分支覆盖。在上面的代码中,一次调用一个大的绿色Foo,一个调用一个小红色的Foo给前者,但仍然没有发现大红色的bug。

并不是说这个例子是有史以来最好的OO设计,但很少看到代码覆盖暗示路径覆盖的代码。即使它确实意味着在您的代码中,它并不意味着库或系统中的所有代码或所有路径都被覆盖,您的程序可能会使用它。原则上,您需要100%覆盖程序中所有可能的状态来做到这一点(并因此确保例如在任何情况下您都无法使用无效参数调用,导致图书馆或系统中的错误代码无法获得),这通常是不可行的。

0

测试是绝对必要的。执行也是必须要考虑的。

如果你以某种没有在你的测试中的方式实现某些东西,那么问题就可能发生。

当您测试的数据与将要流经应用程序的数据无关时,也可能发生问题。

所以,代码覆盖率是必要的。但不如真人的真实测试。

+0

“当您测试的数据与将要流经应用程序的数据无关时,也可能发生问题。”你会如何编写测试来为使用泛型的类实现这一目标? – 2008-10-04 14:25:42