进行单元测试时,100%代码覆盖范围真的是一件非常好的事情吗? [关闭
-
30-09-2019 - |
题
我总是了解到,使用单位测试进行最大代码覆盖范围是 好的. 。我还听到来自微软等大公司的开发人员说,他们编写的测试代码行比可执行代码本身更多。
现在, 真的很棒吗? 有时看起来像个 完全损失时间 这有唯一的影响 使维护更加困难?
例如,假设我有一种方法 DisplayBooks()
这填充了数据库中的书籍列表。产品要求证明,如果商店中有一百多本书, 只能显示一百个.
所以,有了TDD,
- 我将首先进行单位测试
BooksLimit()
它将在数据库中保存200本书,请致电DisplayBooks()
, ,做一个Assert.AreEqual(100, DisplayedBooks.Count)
. - 然后我将测试是否失败,
- 那我会改变
DisplayBooks()
通过将结果的极限设置为100,并且 - 最后,我将重新运行测试,看看它是否成功。
好吧,直接迈出第三步并不要容易得多,而且永远不会做 BooksLimit()
单位测试?难道不是更敏捷的,当要求从100读物更改为200本书时,只会更改一个字符,而不是更改测试,而是运行测试以检查是否失败,更改代码和运行测试以检查其是否成功?
注意:假设代码已充分记录。否则,有些人可能会说,他们是正确的,进行完整的单位测试将有助于了解缺乏文档的代码。实际上,有一个 BooksLimit()
单位测试将非常清楚地显示出最大数量的书籍要显示,并且最大数字为100。踏入非单元测试代码将更加困难,因为可以实现此类限制 for (int bookIndex = 0; bookIndex < 100; ...
或者 foreach ... if (count >= 100) break;
.
解决方案
好吧,直接进入第三步,并且绝不会使Bookslimit()单位测试更容易?
是的...如果您不花任何时间编写测试,那么您将花费更少的时间编写测试。您的项目可能需要 更长 总体而言,因为您会花费大量时间调试,但是也许这更容易向您的经理解释?如果是这样...找新工作!测试对于提高对软件的信心至关重要。
当您有很多代码时,Unitesting赋予最大价值。使用几个不统一的课程调试简单的家庭作业很容易。一旦您走出世界,就可以在数百万行的代码库中工作 - 您将需要它。您根本无法在所有内容中迈出一步。您根本无法理解一切。您需要知道您取决于工作的课程。您需要知道有人说“我只是要对行为做出这种改变……因为我需要它”,但是他们忘记了,还有两百个用途取决于这种行为。统一有助于防止这一点。
关于使维护更加努力: 没门! 我不能充分利用它。
如果您是唯一从事您项目的人,那么是的,您可能会认为这一点。但这是疯狂的谈话!尝试在没有UNINGEST的情况下加快30K线项目的速度。尝试添加需要对代码进行重大更改的功能。有 没自信 您不会打破其他工程师做出的隐式假设。对于维护者(或现有项目上的新开发人员)而言,Unitests是关键。我依靠Unitests进行文档,行为,假设,告诉我何时破坏了某些东西(我认为这是无关的)。有时,书写不佳的API的书面测试不佳,可能是一场噩梦,因为测试一直吸收。最终,您将要重构此代码并修复该代码,但是您的用户也会感谢您 - 因此,您的API会更容易使用。
覆盖范围:
对我来说,这不是100%的测试覆盖率。 100%覆盖范围找不到所有错误,请考虑两个功能 if
语句:
// Will return a number less than or equal to 3
int Bar(bool cond1, bool cond2) {
int b;
if (cond1) {
b++;
} else {
b+=2;
}
if (cond2) {
b+=2;
} else {
b++;
}
}
现在考虑我写一个测试测试:
EXPECT_EQ(3, Bar(true, true));
EXPECT_EQ(3, Bar(false, false));
那是100%的覆盖范围。这也是不符合合同的功能 - Bar(false, true);
失败,因为它返回4.因此,“完整的覆盖范围”不是最终目标。
老实说,我会跳过测试 BooksLimit()
. 。它返回一个常数,因此可能不值得写它们(应该在写作时进行测试 DisplayBooks()
)。当某人决定(错误地)计算出货架尺寸的限制并且不再满足我们的要求时,我可能会感到难过。以前,我被“不值得测试”烧死了。去年,我写了一些我对我的同事说的代码:“这堂课主要是数据,不需要测试”。它有一种方法。它有一个错误。它开始生产。它在深夜打了我们。我感到很愚蠢。所以我写了测试。然后,我对哪些代码构成“不值得测试”而漫长而艰难。没有太多。
因此,是的,您可以跳过一些测试。 100%的测试覆盖范围很棒,但这并不意味着您的软件是完美的。这一切都归结为对变革的信心。
如果我放 class A
, class B
和 class C
在一起,我发现一些不起作用的东西,我想花时间调试这三个吗?不,我想知道 A
和 B
已经达到了他们的合同(通过Unitests)和我的新代码 class C
可能坏了。所以我很统一。如果我不统一,我什至怎么知道它被打破了?通过单击一些按钮并尝试新代码?那很好,但还不够。一旦您的程序扩展,就不可能重新运行所有手动测试来检查一切是否正常。这就是为什么UNITSEST通常也会自动进行测试的人的原因。告诉我“通行证”或“失败”,不要告诉我“输出是……”。
好的,要去写更多测试...
其他提示
100%的单位测试覆盖范围通常是代码气味,这表明某人在覆盖范围工具中的绿色条上已经超过了所有强迫症,而不是做更有用的事情。
大约85%的地方是最佳地点,其中一个测试更常见,而不是表明实际或潜在的问题,而不是仅仅是任何文本更改而不是内部评论标记的必然结果。如果您的假设是“代码就是它的本质,则没有任何有用的假设,如果它以任何方式不同,那将是其他的。这是通过评论意见的检查时间来解决的问题,而不是单位测试。
我希望有一些工具可以让您指定目标覆盖范围。然后,如果您不小心浏览它,请用黄色/橙色/红色显示东西,以推动您删除一些虚假的额外测试。
查看孤立的问题时,您是完全正确的。但是单位测试是关于涵盖您对某个代码的所有意图。
基本上,单元测试制定了您的意图。有了越来越多的意图,始终可以根据到目前为止所做的所有意图检查要测试的代码的行为。每当进行更改时,您都可以证明没有副作用破坏现有意图。新发现的错误不过是代码不持有的(隐性)意图,因此您将自己的意图作为新测试(首先失败)和修复程序。
对于一次性代码,单位测试确实不值得付出努力,因为预计不会进行重大更改。但是,对于要维护或用作其他代码组件的任何代码的任何块,保证对任何新版本的所有意图都值得很多(就手动尝试检查副作用而减少的努力而言) 。
单位测试实际节省时间的转折点,因此金钱取决于代码的复杂性,但是在只有很少的更改迭代后,通常会有一个临界点。另外,最后但并非最不重要的一点使您可以在不损害产品质量的情况下运输修复和更改速度。
代码覆盖范围和良好的软件之间没有任何超凡关系。您可以轻松地想象具有100%(或关闭)代码覆盖的代码,并且仍然包含很多错误。 (这并不意味着测试不好!)
您关于“根本没有测试”方法敏捷性的问题仅是一个很好的方法(对于简短的角度来看)(这意味着如果您打算更长的时间构建程序,这很可能不好)。从我的经验中,我知道,当您的项目变得越来越大,并且在某个阶段您需要进行重大更改时,这种简单的测试非常有用。当你对自己说时,这可能是妈妈 ``这是一个很好的决定,花了几分钟的时间来编写我刚刚介绍的小错误的小测试!''.
我最近是代码覆盖范围的忠实拥护者,但现在它转向了类似的东西 “问题覆盖范围” 方法。这意味着您的测试应涵盖所有发现的问题和错误 “代码行”. 。无需做一个 “代码覆盖竞赛”.
我了解数字测试的“敏捷”单词 '有助于我构建良好软件而不是浪费时间编写不必要的代码的测试数量' 而不是“ 100%覆盖范围”或“根本没有测试”。这是非常主观的,它基于您的经验,团队,技术和许多其他因素。
“ 100%代码覆盖”的心理副作用是,您可能认为您的代码没有错误,从来都不是真的:)
我同意@Soru,100%的测试覆盖范围不是合理的目标。
我不认为可以存在任何工具或指标可以告诉您“正确”的覆盖范围。当我上研究生时,我的论文顾问的工作是设计“突变”代码的测试覆盖范围。他参加了一套测试,然后运行一个自动程序以在测试的源代码中犯错误。这个想法是,突变的代码包含在现实世界中发现的错误,因此,一个发现损坏代码比例最高的测试套件是获胜者。
尽管他的论文被接受,而他现在是一所主要工程学校的教授,但他也没有找到:
1)最佳测试覆盖范围的神奇数量2)任何可以发现100%错误的套件。
请注意,目标是找到100%的错误,而不是找到100%的覆盖范围。
@Soru的85%是正确的,是讨论的主题。我没有能够评估更好的数字是80%还是90%或其他任何东西。但是,作为一项工作评估,有85%的人对我有正确的看法。
对不起我的英语不好。
100%代码覆盖范围是一种管理生理障碍,可以人为地打动利益相关者。我们进行测试是因为那里有一些复杂的代码可以导致缺陷。因此,我们需要确保复杂的代码具有测试用例,测试和缺陷在现场之前修复。
我们应该旨在测试复杂的事情,而不仅仅是一切。现在,该复合物需要用一些度量数来表达,这些度量可能是醚环的复杂性,代码线,聚合,耦合等,或者可能对所有上述内容的高潮。如果我们发现高度较高的指标,我们需要确保涵盖代码的部分。以下是我的文章,涵盖了代码覆盖的最佳%。
首先很难获得100%的100%!而且,即使您在涵盖了一块代码时也要做,也不意味着它正在做应该做的事情,除非您的测试主张所有可能的输入和输出(这几乎是不可能的)。
因此,我不会认为一件软件是好的,仅仅是因为它具有100%的代码覆盖范围,但是代码覆盖范围仍然是一件好事。
好吧,直接进入第三步,并且绝不会使Bookslimit()单位测试更容易?
好吧,在那里进行该测试使您非常有信心,如果有人更改代码和测试失败,您会注意到新代码出现问题,因此您避免了应用程序中的任何势力错误
当客户决定将限制更改为200时,祝您好运找到与该看似微不足道的测试有关的错误。特别是,当您的代码中有其他100个变量时,还有其他5位开发人员正在处理代码,从而依赖于该微小的信息。
我的观点:如果它对业务价值很有价值(或者,如果您不喜欢名称,对项目的核心非常重要),请对其进行测试。仅在没有可能(或便宜的)测试方式(例如UI或用户互动)或确定不编写测试的影响时丢弃。对于具有模糊或快速改变需求的项目(如我所痛苦地发现),这使得更加真实。
对于您提出的另一个示例,建议是测试边界值。因此,您只能将测试限制在四个值中:0,0和Bookslimit之间的一些神奇数字,Bookslimit和更高的数字。
而且,正如其他人所说的那样,进行测试,但是100%积极的事情可能会失败。