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()在尝试调用事件之前不检查事件是否有任何处理程序。这将导致 null 取消引用,这将永远不会被我们的任何测试捕获,因为它们都默认附加了一个事件处理程序。但同样,代码覆盖率工具仍会报告完全覆盖率。

这只是我手头的“真实世界示例”,但我突然想到,即使您的代码 100%“覆盖”,也可能会漏掉更多此类错误,但这仍然不能转化为 100% 测试. 在编写测试时,我们是否应该对这种工具报告的覆盖率持保留态度?是否有其他类型的工具可以捕捉这些漏洞?

4

7 回答 7

4

我不会说“半信半疑”(代码覆盖率有很多实用性),而是引用我自己的话

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

· 即使有 100% 的块覆盖率,在选择执行哪些块的条件中仍然会出现错误。

· 即使100%的块覆盖+100%的圆弧覆盖,直线代码仍然会出现错误。

· 即使有 100% 的块覆盖率 + 100% 的弧线覆盖率 + 100% 无错误的至少一条路径的直线代码,仍然会有输入数据以表现出更多错误的方式执行路径/循环.

(从这里

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

于 2008-10-04T13:15:10.797 回答
4

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

另请注意,代码覆盖率和路径覆盖率之间存在差异:

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

如果您将一个大的绿色 Foo 作为测试用例传递到该代码中,您将获得 100% 的代码覆盖率。但就你所知,一个大的红色 Foo 会导致系统崩溃,因为 accountForBigness 错误地假设某个指针是非空的,只有 accountForGreenness 才将它设为非空。您没有 100% 的路径覆盖,因为您没有覆盖跳过对 accountForGreenness 的调用而不是对 accountForBigness 的调用的路径。

也有可能在没有 100% 路径覆盖的情况下获得 100% 的分支覆盖。在上面的代码中,一个带有绿色大 Foo 的调用和一个带有红色小 Foo 的调用给出了前者,但仍然没有捕捉到大的红色错误。

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

于 2008-10-04T14:12:53.300 回答
2

在编写测试时,我们是否应该对这种工具报告的覆盖率持保留态度?

绝对地。覆盖率工具仅告诉您代码中实际运行的行数比例。它没有说明这些行的测试有多彻底。有些代码行只需要测试一次或两次,但有些代码需要在广泛的输入范围内进行测试。覆盖工具无法区分。

于 2008-10-04T13:05:09.960 回答
1

此外,如果测试驱动程序只是在没有关于结果正确性的有意义断言的情况下执行代码,那么 100% 的测试覆盖率本身并没有多大意义。

于 2008-10-04T13:09:21.963 回答
0

覆盖率仅在识别根本没有经过测试的代码时才真正有用。它并没有告诉您太多有关已涵盖的代码的信息。

于 2008-10-04T13:12:27.603 回答
0

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

于 2008-10-04T14:01:50.640 回答
0

测试是绝对必要的。也必须保持一致的是实施。

如果您以未在测试中的方式实现某些东西……那么问题可能就在那里发生。

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

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

于 2008-10-04T14:23:57.413 回答