上周,我与我的长期朋友(有时是壁球伙伴)Freddy Mallet就代码覆盖率进行了激烈但有趣的Twitter辩论 。
我的意思是:多数注重质量的软件工程师所珍视的代码覆盖率指标不能保证任何事情。 因此,达到80%(或100%)的代码覆盖率并自吹自bra与吹拂风一样有用。 当然,在Twitter上进行基于事实的辩论非常困难,因为140个字符对任何论点都施加了严格限制。 本文试图在无限的空间内写下我的论点。
原始代码覆盖率的无用之处可以很容易地证明。 让我们举一个简单的示例,其中包含以下要测试的类:
publicclassPassFilter{
privateintlimit;
publicPassFilter(intlimit){
this.limit=limit;
}
publicbooleanfilter(inti){
returni<limit;
}
}
此类非常简单,无需评论。 可能的测试如下:
publicclassPassFilterTest{
privatePassFilterpassFilterFive;
@BeforeMethod
protectedvoidsetUp(){
passFilterFive=newPassFilter(5);
}
@Test
publicvoidshould_pass_when_filtering_one(){
booleanresult=passFilterFive.filter(1);
}
@Test
publicvoidshould_not_pass_when_filtering_ten(){
booleanresult=passFilterFive.filter(10);
}
}
该测试类将愉快地返回100%的代码覆盖率和100%的行覆盖率 :执行测试将遍历所有代码行以及单个分支的两侧。 生活不甜美吗? 可惜没有主张。 他们可能被无法达到先前商定的代码覆盖率指标的承包商故意“遗忘”了。 让我们给承包商带来疑问的好处,并假设程序员是真诚的-并提出断言:
publicclassPassFilterTest{
privatePassFilterpassFilterFive;
@BeforeMethod
protectedvoidsetUp(){
passFilterFive=newPassFilter(5);
}
@Test
publicvoidshould_pass_when_filtering_one(){
booleanresult=passFilterFive.filter(1);
Assert.assertTrue(result);
}
@Test
publicvoidshould_not_pass_when_filtering_ten(){
booleanresult=passFilterFive.filter(10);
Assert.assertFalse(result);
}
}
仍然100%的代码覆盖率和100%的行覆盖率-这次是“真实的”断言! 但这仍然没有用...这是众所周知的事实,开发人员倾向于测试合格案例。 在这种情况下,这两种情况使用的参数分别为1和10,而潜在的bug恰好在5的阈值上(过滤器是否应使用此值让其通过?)。
总之,原始代码覆盖率仅保证最大的代码覆盖率。 如果是0%,那么当然是0%; 但是,只有80%的情况,它什么也不会给您带来任何好处....只是至多 80%的代码被覆盖的保险。 但也可以介于60%,40%甚至0%之间。 仅暗示最大值的指标有什么好处? 实际上,从这个角度来看,代码覆盖率是一个Bloom Filter 。 恕我直言,确保测试用例和相关测试覆盖范围真正有意义的唯一方法是使用Mutation Testing 。 有关突变测试的基本介绍,请查看我在JavaZone 上的“突变测试简介”演讲(10分钟)。
好消息是,突变测试不是书呆子科学家才知道的某种学术论文,Java中有一些工具可以立即开始使用它。 使用先前的测试配置PIT将产生以下结果:
该报告指出了要杀死的剩余突变体及其关联的行(第12行),很容易添加缺少的测试用例:
@Test
publicvoidshould_not_pass_when_filtering_five(){
booleanresult=passFilterFive.filter(5);
Assert.assertFalse(result);
}
既然我们已经毫无疑问地证明了变异测试的价值,我们该怎么办? 有些人可能尝试了一些反对变异测试的论点。 让我们回顾一下它们:
- 变异测试需要很长时间才能执行。 当然,所有可能突变的组合比标准单元测试要花费更长的时间-单元测试必须在10分钟以内。 但是,这不是问题,因为代码覆盖率不是每个构建都必须检查的指标:每晚构建就足够了。
- 变异测试需要很长时间才能分析结果。 也是正确的...但是,如前所述,什么时候分析代码覆盖率结果仅暗示最大可能的代码覆盖率?
一方面,原始的代码覆盖率指标仅在太低时才有意义-太高时需要进一步分析。 另一方面,变异测试可让您对代码覆盖率指标充满信心,而无需支付额外费用 。 其余的取决于你...
翻译自: https://blog.frankel.ch/your-code-coverage-metric-is-not-meaningful/