将我当前的代码项目转换为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%的测试。在编写测试时,我们是否应该接受这样一个工具所报告的覆盖率呢?还有其他工具可以抓住这些洞吗?
发布于 2008-10-04 13:15:10
我不会说“带点盐”(代码覆盖率有很多实用工具),而是引用我自己的话
TDD和代码覆盖率并不是万灵药: 即使有了100%的块覆盖率,在选择执行哪些块的条件中仍然会出现错误。 ·即使是100%的块覆盖+ 100%的弧线覆盖,直线代码仍然会出现错误。 即使有了100%的块覆盖率+ 100%的弧覆盖率+ 100%的无错误的单路径直线代码,仍然会有以显示更多错误的方式执行路径/循环的输入数据。
(来自这里)
虽然可能有一些工具可以提供改进,但我认为更高级的部分是代码覆盖只是确保产品质量的整体测试策略的一部分。
发布于 2008-10-04 14:12:53
<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的调用给出了前者,但是仍然没有捕获大的、红色的bug。
这个例子并不是有史以来最好的OO设计,但是很少看到代码覆盖意味着路径覆盖的代码。即使它确实意味着在您的代码中,它并不意味着您的程序可能使用的所有代码或库或系统中的所有路径都包括在内。原则上,您需要100%覆盖程序的所有可能状态(因此确保在任何情况下都不使用无效的参数调用,从而导致在库或系统中捕获错误的代码无法达到),这通常是不可行的。
发布于 2008-10-04 13:05:09
在编写测试时,我们是否应该接受这样一个工具所报告的覆盖率呢?
绝对一点儿没错。覆盖率工具只告诉您代码中实际在测试期间运行的行的比例。但这并没有说明这些测试到底有多彻底。有些代码行只需要测试一两次,但有些代码需要在广泛的输入范围内进行测试。覆盖工具无法区分不同之处。
https://stackoverflow.com/questions/170297
复制相似问题