单元测试的合理代码覆盖率是多少(以及为什么)?

单元测试的合理代码覆盖率是多少(以及为什么)?

What is a reasonable code coverage % for unit tests (and why)?

如果您要为单元测试规定最低百分比的代码覆盖率,即使是作为提交到存储库的需求,那它会是什么?

请解释你是如何得出答案的(因为如果你所做的只是选择一个数字,那么我就可以自己完成这一切;)


阿尔贝托·萨沃亚的这篇散文恰恰回答了这个问题(以一种非常有趣的方式!):

http://www.artima.com/forums/flat.jsp?论坛=106&thread=204677

Testivus On Test Coverage

Early one morning, a programmer asked
the great master:

"I am ready to write some unit tests. What code coverage should I aim
for?"

The great master replied:

"Don’t worry about coverage, just write some good tests."

The programmer smiled, bowed, and
left.

...

Later that day, a second programmer
asked the same question.

The great master pointed at a pot of
boiling water and said:

"How many grains of rice should I put in that pot?"

The programmer, looking puzzled,
replied:

"How can I possibly tell you? It depends on how many people you need to
feed, how hungry they are, what other
food you are serving, how much rice
you have available, and so on."

"Exactly," said the great master.

The second programmer smiled, bowed,
and left.

...

Toward the end of the day, a third
programmer came and asked the same
question about code coverage.

"Eighty percent and no less!" Replied the master in a stern voice,
pounding his fist on the table.

The third programmer smiled, bowed,
and left.

...

After this last reply, a young
apprentice approached the great
master:

"Great master, today I overheard you answer the same question about
code coverage with three different
answers. Why?"

The great master stood up from his
chair:

"Come get some fresh tea with me and let’s talk about it."

After they filled their cups with
smoking hot green tea, the great
master began to answer:

"The first programmer is new and just getting started with testing.
Right now he has a lot of code and no
tests. He has a long way to go;
focusing on code coverage at this time
would be depressing and quite useless.
He’s better off just getting used to
writing and running some tests. He can
worry about coverage later."

"The second programmer, on the other hand, is quite experience both
at programming and testing. When I
replied by asking her how many grains
of rice I should put in a pot, I
helped her realize that the amount of
testing necessary depends on a number
of factors, and she knows those
factors better than I do – it’s her
code after all. There is no single,
simple, answer, and she’s smart enough
to handle the truth and work with
that."

"I see," said the young apprentice,
"but if there is no single simple
answer, then why did you answer the
third programmer ‘Eighty percent and
no less’?"

The great master laughed so hard and
loud that his belly, evidence that he
drank more than just green tea,
flopped up and down.

"The third programmer wants only simple answers – even when there are
no simple answers … and then does not
follow them anyway."

The young apprentice and the grizzled
great master finished drinking their
tea in contemplative silence.


如果100%覆盖率是您的目标(而不是100%测试所有特性),那么代码覆盖率是一个误导性指标。

  • 你只需打一次就可以得到100%的分数。但是,您仍然可能会错过测试命中这些行的特定序列(逻辑路径)。
  • 您无法获得100%,但仍然测试了所有80%/freq使用的代码路径。通过测试每个"throw exceptiontypex"或类似的防御性编程保护,你会发现"很高兴拥有"而不是"必须拥有"。

因此,请相信您自己或您的开发人员是彻底的,并通过他们的代码覆盖每一条路径。实事求是,不要追求神奇的100%覆盖率。如果你的代码是TDD的,你应该得到90%以上的覆盖率作为奖励。使用代码覆盖率突出显示您错过的代码块(如果是TDD,则不应该发生)。因为编写代码只是为了通过测试。没有合作伙伴测试,任何代码都不能存在。)


代码覆盖率很好,但功能覆盖率更好。我不相信能覆盖我写的每一行。但我确实相信,要为我想要提供的所有功能编写100%的测试覆盖率(即使对于我自己附带的、在会议期间没有讨论过的特别酷的功能)。

我不在乎我是否会有测试中没有涉及的代码,但我关心我是否会重构我的代码并最终得到不同的行为。因此,100%的功能覆盖率是我唯一的目标。


公认的答案很有意义——没有一个数字可以作为每个项目的标准。有些项目不需要这样的标准。我认为,在我看来,接受的答案不足以说明一个人如何为一个给定的项目做出决定。好的。

我想试试看。我不是测试工程方面的专家,很高兴看到一个更明智的答案。好的。何时设置代码覆盖率要求

首先,你为什么要把这样一个标准强加在第一位?一般来说,当你想在你的过程中引入经验的信心时。我所说的"经验信心"是什么意思?好吧,真正的目标正确性。对于大多数软件,我们不可能在所有输入中都知道这一点,所以我们决定说代码是经过良好测试的。这一点更为清楚,但仍然是一个主观标准:无论你是否达到了这一标准,它都会一直公开辩论。这些辩论是有用的,应该发生,但它们也暴露出不确定性。好的。

代码覆盖率是一个客观的度量:一旦您看到覆盖率报告,就不会对是否满足标准产生歧义。它证明了正确性吗?一点也不,但它与测试代码的好坏有着明确的关系,这反过来又是我们增强对其正确性信心的最佳方法。代码覆盖率是我们所关心的不可测量的特性的可测量的近似值。好的。

一些特殊情况下,有经验标准可以增加价值:好的。

  • 使利益相关者满意。对于许多项目,有许多对软件质量感兴趣的参与者可能不参与软件的日常开发(经理、技术主管等),他们说"我们要编写我们真正需要的所有测试"并不令人信服:他们要么需要完全信任,要么需要持续的密切监督(assumi他们甚至拥有这样做的技术理解。)提供可测量的标准并解释他们如何合理地接近实际目标是更好的。
  • 规范团队行为。撇开利益相关者不谈,如果你在一个团队中工作,在这个团队中有很多人在编写代码和测试,那么对于什么是合格的"经过良好测试的",就存在着不确定性的空间。你的所有同事对什么样的测试水平足够好有相同的看法吗?大概不会。你怎么协调这个?找到一个你们都能同意的指标,并接受它作为一个合理的近似值。这在大型团队中尤其有用(但并非完全有用),例如,在大型团队中,领导可能无法直接监督初级开发人员。信任网络也很重要,但如果没有客观的衡量标准,即使每个人都是善意的,团队行为也很容易变得不一致。
  • 保持诚实。即使您是项目的唯一开发人员和利益相关者,您也可能为软件考虑到某些特性。您可以使用代码覆盖率作为一个合理的近似值,让机器为您测量代码覆盖率,而不是对软件测试的好坏(这需要工作)进行持续的主观评估。

使用哪些指标

代码覆盖率不是一个单一的度量标准;有几种不同的度量覆盖率的方法。您可以根据哪个标准来设置标准,这取决于您使用该标准来满足什么。好的。

我将使用两个常用度量作为示例,说明何时可以使用它们来设置标准:好的。

  • 语句覆盖率:测试期间执行的语句的百分比是多少?有助于了解代码的物理覆盖范围:我编写的代码中有多少是经过实际测试的?
    • 这种覆盖支持较弱的正确性论证,但也更容易实现。如果您只是使用代码覆盖率来确保测试结果(而不是作为测试质量的指标),那么语句覆盖率可能就足够了。
  • 分支覆盖率:当存在分支逻辑(如if)时,是否对两个分支都进行了评估?这样可以更好地理解代码的逻辑覆盖范围:我的代码可能采用了多少种可能的路径进行了测试?
    • 这种覆盖率是一个更好的指标,表明一个程序已经通过一组全面的输入进行了测试。如果您使用代码覆盖率作为您对正确性信心的最佳经验近似值,那么应该基于分支覆盖率或类似情况设置标准。

还有许多其他指标(行覆盖率类似于语句覆盖率,但对于多行语句会产生不同的数值结果;条件覆盖率和路径覆盖率类似于分支覆盖率,但反映了可能遇到的程序执行排列的更详细视图)。好的。需要多少百分比

最后,回到最初的问题:如果您设置了代码覆盖率标准,那么这个数字应该是什么?好的。

希望在这一点上我们可以清楚地看到,我们要讨论的是一个近似值,所以我们选择的任何数字都是固有的近似值。好的。

一些可以选择的数字:好的。

  • 100%。您可以选择此选项,因为您希望确保所有内容都经过测试。这并不能让您对测试质量有任何了解,但确实告诉您,某些质量的测试再次触及了每一条语句(或分支等),这又回到了信心的程度:如果覆盖率低于100%,您就知道代码的某些子集未经测试。
    • 有些人可能认为这很愚蠢,您应该只测试代码中真正重要的部分。我认为您还应该只维护代码中真正重要的部分。代码覆盖率也可以通过删除未测试的代码来提高。
  • 99%(或95%,90年代的其他数字)适用于希望传递类似100%的信心的情况,但给自己留一些余地,不要担心偶尔难以测试的代码角。
  • 80%。我已经看到这个数字被使用过几次了,不完全知道它是从哪里来的。我认为这可能是对80-20规则的一种奇怪的盗用;一般来说,这里的目的是证明您的大多数代码都经过了测试。(是的,51%也是"大多数",但80%更能反映大多数人的意思。)这适用于"经过良好测试"不是高优先级(您不想在低值测试上浪费精力),但足够优先的情况下,您仍然希望有一些标准到位。

我在实践中还没有看到低于80%的数字,很难想象一个可以设定它们的情况。这些标准的作用是增加对正确性的信心,低于80%的数字并不是特别令人鼓舞的信心。(是的,这是主观的,但同样的,我们的想法是在设定标准时做出一次主观的选择,然后进行客观的测量。)好的。其他音符

上面假设正确性是目标。代码覆盖率只是信息;它可能与其他目标相关。例如,如果您关心可维护性,那么您可能关心松耦合,松耦合可以通过可测试性来证明,而松耦合又可以通过代码覆盖率来度量(以某些方式)。因此,您的代码覆盖率标准也为近似"可维护性"的质量提供了经验基础。好的。好啊。


我最喜欢的代码覆盖率是100%,带星号。星号之所以出现,是因为我更喜欢使用允许我将某些行标记为"不算数"的行的工具。如果我已经覆盖了100%的"计数"行,我就完成了。

基本流程是:

  • 我编写测试来练习我能想到的所有功能和边缘案例(通常从文档中工作)。
  • 我运行代码覆盖工具
  • 我检查没有覆盖的任何线路或路径,以及我认为不重要或不可到达的任何线路或路径(由于防御编程),我标记为不计数。
  • 我编写新的测试来覆盖缺失的行,如果没有提到这些边缘情况,我会改进文档。
  • 这样一来,如果我和我的合作者在未来添加新代码或更改测试,就有一条很好的线告诉我们是否遗漏了一些重要的东西——覆盖率下降到100%以下。但是,它还提供了处理不同测试优先级的灵活性。


    我想分享一下关于测试覆盖率的另一个轶事。

    我们有一个巨大的项目,在Twitter上,我注意到,通过700个单元测试,我们只有20%的代码覆盖率。

    斯科特·汉塞尔曼用智慧的话语回答:

    Is it the RIGHT 20%? Is it the 20%
    that represents the code your users
    hit the most? You might add 50 more
    tests and only add 2%.

    同样,它回到了我关于代码覆盖率答案的测试中。你应该在锅里放多少米?这要看情况而定。


    对于一个设计良好的系统,从一开始就由单元测试驱动开发,我会说85%是一个相当低的数字。设计为可测试的小类不应该比这更难覆盖。好的。

    这个问题很容易被忽略,比如:好的。

    • 被覆盖的行不等于被测试的逻辑,一个不应该读取太多的百分比。

    是的,但是关于代码覆盖率还有一些重要的问题需要考虑。根据我的经验,这个度量标准在正确使用时实际上非常有用。尽管如此,我还没有看到所有的系统,我相信在很多系统中,很难看到代码覆盖率分析增加了任何实际价值。代码看起来如此不同,可用测试框架的范围也可能不同。好的。

    另外,我的推理主要涉及相当短的测试反馈循环。对于我正在开发的产品,最短的反馈循环是相当灵活的,涵盖了从类测试到进程间信令的所有内容。测试可交付的子产品通常需要5分钟,对于如此短的反馈循环,确实可以使用测试结果(特别是我们在这里看到的代码覆盖率度量)来拒绝或接受存储库中的提交。好的。

    当使用代码覆盖率度量时,您不应该只拥有必须满足的固定(任意)百分比。在我看来,这样做并不能给您代码覆盖率分析带来真正的好处。相反,定义以下指标:好的。

    • 低水位线(LWM),试验系统中出现的未覆盖管线的最低数量。
    • 高水位线(HWM),被测系统有史以来的最高代码覆盖率

    只有当我们不在LWM之上,也不在HWM之下时,才能添加新代码。换言之,不允许降低代码覆盖率,应该覆盖新代码。注意我说的应该和不必(解释如下)。好的。

    但这难道不意味着你将不可能清除那些你已经不再使用的经过充分测试的旧垃圾吗?是的,这就是为什么你必须务实对待这些事情。有些情况下,规则必须被打破,但对于您典型的日常集成,我的经验是,这些指标非常有用。它们给出了以下两个含义。好的。

    • 可测试代码已升级。当添加新代码时,您必须努力使代码可测试,因为您必须尝试用您的测试用例覆盖所有代码。可测试代码通常是一件好事。好的。

    • 遗留代码的测试覆盖率随着时间的推移而增加。当添加新代码而无法用测试用例覆盖它时,可以尝试覆盖一些遗留代码,而不是绕过LWM规则。这种有时必要的欺骗至少会产生积极的副作用,即遗留代码的覆盖范围将随着时间的推移而增加,这使得这些规则在实践中看起来非常实用。好的。

    同样,如果反馈循环太长,那么在集成过程中设置类似的东西可能是完全不现实的。好的。

    我还想提到代码覆盖度量的两个更一般的好处。好的。

    • 代码覆盖率分析是动态代码分析的一部分(与静态代码分析不同,即lint)。动态代码分析过程中发现的问题(通过purify系列等工具,http://www-03.ibm.com/software/products/en/rational-purify-family)是未初始化的内存读取(umr)、内存泄漏等。只有在代码被执行的测试用例覆盖时,才能发现这些问题。在测试用例中最难覆盖的代码通常是系统中的异常情况,但是如果您希望系统正常地失败(即错误跟踪而不是崩溃),那么您可能还需要在动态代码分析中努力覆盖异常情况。如果运气不好的话,UMR会导致SegFault或更糟。好的。

    • 人们以100%地保留新代码为荣,并且人们以与其他实现问题类似的热情讨论测试问题。如何以更可测试的方式编写此函数?你将如何设法掩盖这个异常情况等?好的。

    为了完整性,是否定的。好的。

    • 在一个有很多开发人员参与的大型项目中,每个人都不一定是测试天才。有些人倾向于使用代码覆盖率度量来证明代码是经过测试的,这与事实相差甚远,正如许多其他问题的答案中提到的那样。这是一个度量标准,如果使用得当,可以给您带来一些好处,但是如果使用不当,实际上会导致糟糕的测试。除了上面提到的非常有价值的副作用外,一条被覆盖的行只表明被测系统可以到达该行以获取一些输入数据,并且它可以在不挂起或崩溃的情况下执行。

    好啊。


    如果这是一个完美的世界,100%的代码将被单元测试覆盖。然而,由于这不是一个完美的世界,这是一个你有时间做什么的问题。因此,我建议少关注特定的百分比,多关注关键领域。如果您的代码写得很好(或者至少是一个合理的复制品),那么在API暴露于其他代码的地方应该有几个关键点。

    将您的测试工作集中在这些API上。确保API 1)有良好的文档记录,2)编写了与文档匹配的测试用例。如果预期的结果与文档不匹配,那么您的代码、文档或测试用例中都有一个bug。所有这些都是很好的审查。

    祝你好运!


    许多商店不重视测试,所以如果你高于零,至少会有一些价值的增值-所以可以说,非零并不坏,因为许多商店仍然是零。

    在.NET世界里,人们经常引用80%的话作为理由。但他们在解决方案层面上这样说。我更喜欢在项目级别进行度量:如果您有Selenium等或手动测试,30%对于UI项目可能是好的,20%对于数据层项目可能是好的,但是如果不是完全必要的话,95%以上对于业务规则层可能是可以实现的。因此,总体覆盖率可能是60%,但关键业务逻辑可能要高得多。

    我也听说过:追求100%,你会达到80%;但是追求80%,你会达到40%。

    底线:应用80:20规则,让你的应用程序的错误计数指导你。


    85%是登记标准的良好起点。

    我可能会根据测试子系统/组件的关键性,选择各种更高的条作为运输标准。


    当我认为我的代码没有经过足够的单元测试,并且我不确定下一步要测试什么时,我使用覆盖率来帮助我决定下一步要测试什么。

    如果我在单元测试中增加覆盖率-我知道这个单元测试有价值。

    这适用于未涵盖、50%涵盖或97%涵盖的代码。


    代码覆盖率只是另一个度量标准。就其本身而言,这可能是非常误导性的(参见www.thoughtworks.com/insights/blog/are test coverage metrics overrated)。因此,您的目标不应该是实现100%的代码覆盖率,而是确保测试应用程序的所有相关场景。


    我使用cobertura,不管百分比是多少,我建议保持cobertura检查任务中的值是最新的。至少,将totallinerate和totalbrancharate提高到略低于当前覆盖率,但不要降低这些值。还将Ant构建失败属性与此任务联系起来。如果构建由于覆盖率不足而失败,那么您知道有人添加了代码,但没有对其进行测试。例子:

    1
    2
    3
    4
    5
    <cobertura-check linerate="0"
                     branchrate="0"
                     totallinerate="70"
                     totalbranchrate="90"
                     failureproperty="build.failed" />

    如果你已经做了相当长的时间的单元测试,我认为没有理由不接近95%。但是,至少,我一直在用80%的速度工作,即使是刚开始测试的时候。

    这个数字应该只包括项目中编写的代码(不包括框架、插件等),甚至可能排除完全由对外部代码的调用编写的代码组成的某些类。这种呼吁应该被嘲弄。


    一般来说,从我读过的几篇工程卓越最佳实践论文中,80%的单元测试中的新代码是产生最佳回报的关键。超过这个CC%所产生的力的缺陷量会更低。这是许多大公司采用的最佳实践。

    不幸的是,这些结果大多是公司内部的,因此没有公开文献可供参考。


    代码覆盖率很高,但前提是您从中获得的好处大于实现它的成本/努力。

    我们已经按照80%的标准工作了一段时间,但是我们刚刚决定放弃这个标准,转而更加关注我们的测试。专注于复杂的业务逻辑等,

    这个决定是由于我们花在追逐代码覆盖率和维护现有单元测试上的时间越来越多而做出的。我们觉得我们已经到了这样的地步:我们从代码覆盖中获得的好处被认为比我们为实现它所付出的努力要少。


    我对这个难题的答案是,你可以测试的代码有100%的行覆盖率,不能测试的代码有0%的行覆盖率。

    我在python中的当前实践是将.py模块分为两个文件夹:app1/和app2/,当运行单元测试时,计算这两个文件夹的覆盖率,并目视检查(我必须在某一天自动执行此操作)app1的覆盖率为100%,app2的覆盖率为0%。

    当/如果我发现这些数字与标准不符,我会调查并修改代码的设计,使覆盖范围符合标准。

    这意味着我可以建议实现100%的库代码行覆盖率。

    我偶尔也会查看app2/以查看是否可以在那里测试任何代码,如果可以,我可以将其移动到app1中。/

    现在,我不太担心总覆盖率,因为根据项目的大小,总覆盖率可能会有很大的变化,但一般来说,我看到的覆盖率是70%到90%以上。

    使用python,我应该能够设计一个烟雾测试,它可以在测量覆盖率的同时自动运行我的应用程序,并且在将烟雾测试与UnitTest数字结合时,有望获得100%的增长。


    从另一个角度来看覆盖率:写得好、控制流清晰的代码最容易覆盖、最容易读取,而且通常代码的错误最少。通过在头脑中编写清晰和可覆盖的代码,以及通过与代码并行编写单元测试,可以获得最佳的imho结果。


    在我看来,答案是"这取决于你有多少时间"。我试图达到100%,但如果我没有得到它的时间,我不会大惊小怪。

    当我编写单元测试时,与开发生产代码时所戴的帽子相比,我戴的帽子不同。我想一想被测试的代码声称要做什么,以及可能破坏它的情况是什么。

    我通常遵循以下标准或规则:

  • 单元测试应该是一种文档形式,说明我的代码的预期行为是什么,即给定特定输入的预期输出,以及客户端可能希望捕获的异常(我的代码的用户应该知道什么?)

  • 单元测试应该帮助我发现可能还没有想到的假设条件。(如何使我的代码稳定和健壮?)

  • 如果这两条规则不能产生100%的覆盖率,那就这样吧。但一旦有时间,我就分析未发现的块和行,并确定是否还有没有单元测试的测试用例,或者是否需要重构代码以消除不必要的代码。


    我更喜欢使用BDD,它使用自动验收测试、可能的其他集成测试和单元测试的组合。对我来说,问题是自动化测试套件作为一个整体的目标覆盖范围应该是什么。

    除此之外,答案取决于您的方法、语言、测试和覆盖工具。在Ruby或Python中进行TDD时,不难保持100%的覆盖率,这是值得的。100%覆盖比90%左右的覆盖更容易管理。也就是说,当覆盖率缺口出现时(并且在做TDD井时,覆盖率缺口很少,而且通常值得你花时间),要比管理一个覆盖率缺口列表要容易得多,因为你总是有未发现代码的背景,所以你没有找到覆盖率缺口,并且错过覆盖率回归。

    答案还取决于项目的历史。从一开始,我就发现上面的内容在以这种方式管理的项目中是可行的。我已经大大提高了大型遗留项目的覆盖率,这是值得的,但我从来没有发现回到过去填补每个覆盖率差距是可行的,因为旧的未测试代码还没有被很好地理解,不能正确、快速地做到这一点。


    看看crap4j。这是一种比直接代码覆盖稍微复杂的方法。它将代码覆盖率度量与复杂性度量相结合,然后向您展示当前未测试的复杂代码。


    我认为最重要的是了解覆盖率随时间的变化趋势,并了解趋势变化的原因。你认为趋势的变化是好是坏取决于你对原因的分析。


    我认为正确的代码覆盖率的最佳症状是,单元测试帮助修复的具体问题的数量与您创建的单元测试代码的大小相当。


    这必须取决于您所处的应用程序开发生命周期的哪个阶段。

    如果你已经开发了一段时间,已经实现了很多代码,现在才意识到你需要考虑代码覆盖率,那么你必须检查你当前的覆盖率(如果存在的话),然后使用这个基线来设置每个冲刺的里程碑(或者冲刺期间的平均增长),这意味着接受代码DEB在继续提供最终用户价值的同时(至少在我的经验中,如果您增加了测试覆盖率,而最终用户看不到新特性,他们一点也不在乎)。

    根据你的领域,以95%的比例拍摄是不合理的,但我不得不说,平均而言,你会看到85%到90%的平均情况。


    根据代码的关键性,75%-85%是一个很好的经验法则。运输规范的测试肯定要比内部设施等更彻底。


    简短回答:60-80%

    长回答:我认为这完全取决于你的项目的性质。我通常一个项目一个项目地开始测试每一个实际的部分。到项目的第一个"版本"时,根据您正在进行的编程类型,您应该有一个相当好的基本百分比。此时,您可以开始"强制"最小代码覆盖率。


    我认为没有这样的提单规则。应审查代码,特别注意关键细节。但是,如果还没有测试过,它就有一个bug!


    这很大程度上取决于您的应用程序。例如,一些应用程序主要由无法进行单元测试的GUI代码组成。


    几天前我们的目标是大于80%,但是在我们使用了大量生成的代码之后,我们不关心%的年龄,而是让审阅者对所需的覆盖率进行调用。


    根据testivus的文章,我认为答案上下文应该是第二个程序员。从实践的角度来说,我们需要争取参数/目标。我认为,通过分析我们拥有的体系结构、功能(用户案例)的代码,然后提出一个数字,可以在敏捷过程中"测试"这一点。根据我在电信领域的经验,我认为60%是一个很好的检查值。


    推荐阅读