unit testing的合理代码覆盖率是多less(以及为什么)?

如果你要为unit testing规定一个最小百分比的代码覆盖率,甚至可能作为对存储库提交的要求,那将是什么?

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

阿尔贝托·萨沃亚(Alberto Savoia)的这篇散文恰恰回答了这个问题(以一种很好的娱乐方式):

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

testing覆盖面上的testivus

一天早上,程序员问大师:

“我准备写一些unit testing。 我应该瞄准什么代码覆盖?

大师答道:

“不要担心报道,只要写一些好的testing。”

程序员微笑着,鞠躬,离开了。

当天晚些时候,第二位程序员问了同样的问题。

大师指着一壶沸水说:

“我应该在锅里放多less粒米饭?”

程序员看起来不解,答道:

“我怎么可能告诉你? 这取决于你需要喂养多less人,他们多饿,你正在服用什么其他食物,你有多less可用的大米,等等。

“确实,”大师说。

第二位程序员笑了,低头,离开了。

即将结束的时候,第三位程序员来到并提出了关于代码覆盖率的相同问题。

“百分之八十,不能less!”主人用严厉的声音答道,捶着桌上的拳头。

第三位程序员笑了,低头,离开了。

最后一个回复之后,一位年轻的学徒走近大师:

“大师傅,今天我听到你用三个不同的答案回答关于代码覆盖率的同样的问题。 为什么?”

大师从椅子上站了起来:

“来和我一起喝点新鲜茶吧,让我们来谈谈吧。”

他们拿起杯子里的热绿茶,大师开始回答:

“第一个程序员是新手,刚刚开始testing。 现在他有很多代码,没有testing。 他还有很长的路要走。 在这个时候专注于代码覆盖将是令人沮丧和相当无用的。 他习惯于编写和运行一些testing。 他以后可以担心报道。“

“另一方面,第二个程序员在编程和testing方面都有相当的经验。 当我回答问她有多less米饭我应该放在锅里时,我帮助她意识到,必要的检测量取决于许多因素,而且她比我更了解这些因素 – 毕竟这是她的代码。 没有一个单一的,简单的答案,而且她很聪明,能够处理事实真相并进行工作。“

“我明白了,”这个年轻的学徒说,“但是如果没有一个简单的答案,那么你为什么回答第三个程序员'百分之八十,不会less'?

大师笑得如此强烈,他的肚子,他喝了不止绿茶,上下翻倒。

“第三个程序员只需要简单的答案 – 即使没有简单的答案,然后也不会跟着答案。”

那个年轻的学徒和那个花白的大师喝完了沉思的茶。

如果100%覆盖率是您的目标(而不是所有function的100%testing),则代码覆盖率是一个误导性指标。

  • 你可以通过一次击中所有的线来获得100%。 但是,您仍然可能会错过testing这些行被击中的特定序列(逻辑path)。
  • 你无法获得100%,但仍然testing了所有80%/ freq使用的代码path。 经过testing,每一个“抛出ExceptionTypeX”或类似的防守编程后卫,你已经投入是一个“很高兴有”而不是“必须有”

因此,请相信自己或您的开发人员要彻底,并通过他们的代码覆盖每条path。 务实,不追求神奇的100%覆盖。 如果你TDD你的代码,你应该得到一个90%的覆盖面作为奖金。 使用代码覆盖来突出显示你已经错过的代码块(如果你使用TDD,应该不会发生这种情况,因为你只是编写代码来进行testing,如果没有代码testing,就不会有代码存在)。

代码覆盖率很好,但function覆盖率更好。 我不相信我所写的每一行。 但是我确实相信要写100%的testing范围来提供我想提供的所有function(即使是我自己提供的,而且在会议中没有讨论过的额外的function)。

我不在乎是否有代码没有在testing中覆盖,但我会在意如果我会重构我的代码,并最终有不同的行为。 因此,100%的function覆盖是我唯一的目标。

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

基本的过程是:

  1. 我写我的testing,以行使所有我能想到的function和边缘情况(通常从文档工作)。
  2. 我运行代码覆盖工具
  3. 我检查没有覆盖的任何线路或path,以及我认为不重要或无法访问的任何线路(由于防御性编程),我标记为不计算
  4. 我写了新的testing,以涵盖缺失的行,并改善文件,如果没有提到这些边缘情况。

这样,如果我和我的合作者在未来添加新的代码或更改testing,有一条亮线告诉我们,如果我们错过了一些重要的东西 – 覆盖率下降到100%以下。 不过,它也提供了处理不同testing优先级的灵活性。

我希望分享一个关于testing覆盖率的基础知识。

我们有一个巨大的项目,其中,我注意到, 在700个unit testing中,我们只有20%的代码覆盖率 。

Scott Hanselman用智慧的话回答:

这是正确的20%? 是20%代表你的用户打的最多的代码吗? 您可能会添加50个以上的testing,只能添加2%。

再一次,它回到我的Testivus代码覆盖答案。 你要把多less米放进锅里? 这取决于。

被接受的答案有一个好处 – 没有一个数字作为每个项目的标准是有意义的。 有些项目不需要这样的标准。 在我认为所接受的答案不完整的地方,就是在描述某个项目如何做出这个决定。

我会试一试。 我不是testing工程方面的专家,会很高兴看到更明智的答案。

何时设置代码覆盖率要求

首先,你为什么要把这样一个标准放在首位呢? 一般来说,当你想在你的过程中引入实证的信心。 经验信心是什么意思? 那么,真正的目标是否正确 。 对于大多数软件来说,我们不可能在所有input中都知道这一点,所以我们认定代码是经过充分testing的 。 这是更可知的,但仍然是一个主观的标准:它总是会开放辩论是否你遇到了。 这些辩论是有用的,应该发生,但也暴露出不确定性。

代码覆盖率是一个客观的测量:一旦你看到你的覆盖率报告,标准是否被满足是没有意义的。 它certificate是正确的吗? 一点也不,但是它与代码的良好testing有着明确的关系,而这又是我们提高对正确性信心的最好方法。 代码覆盖率是我们关心的不可估量的质量的可衡量的近似值。

具有经验标准的一些具体情况可以增加价值:

  • 满足利益相关者。 对于很多项目来说,有不同的参与者对软件质量感兴趣,他们可能不参与软件的日常开发(pipe理者,技术领导等)。“我们要写所有的我们真正需要的testing“并不令人信服:他们要么完全信任,要么进行密切的监督(假设他们甚至有技术上的理解)。提供可衡量的标准并解释他们如何合理地接近实际目标会更好。
  • 规范团队行为。 除了利益相关者之外,如果你正在一个团队中有多个人正在编写代码和testing,那么对于什么是“经过充分testing”的资格来说,还有一个模棱两可的空间。 你所有的同事都有相同的想法,什么水平的testing是足够好的? 可能不会。 你如何协调这一点? find一个您可以同意的指标,并将其作为合理的近似值接受。 例如,对于大型团队而言,这尤其(但不完全)是有用的,例如,领导者可能没有对初级开发者的直接监督。 信任networking也很重要,但是如果没有客观的测量,即使每个人都是善意的,集体行为也很容易变得不一致。
  • 保持诚实。 即使你是唯一的开发者,也是你项目的唯一利益相关者,你可能会对软件有一定的品质。 您可以使用代码覆盖率作为一个合理的近似值,而不是通过主观评估软件是如何被良好testing(需要工作的),然后让机器为您量身定制。

使用哪些指标

代码覆盖率不是一个单一的指标; 有几种不同的测量覆盖方式。 哪一个你可以设置一个标准取决于你正在使用该标准来满足。

我将使用两个常用指标作为您何时可以使用它们来设置标准的示例:

  • 报表范围 :在testing期间执行的报表有多less百分比? 有用于了解您的代码的物理覆盖率 :我已经写了多less代码实际上testing过?
    • 这种覆盖支持较弱的正确性论据,但也较容易实现。 如果您只是使用代码覆盖来确保事情得到testing(而不是testing质量的指标),那么语句覆盖率就足够了。
  • 分支机构覆盖 :当有分支逻辑(例如一个if )时,是否有两个分支被评估? 这样可以更好地理解代码的逻辑覆盖范围 :我testing的代码可能有多less个可能的path?
    • 这种覆盖范围是一个更好的指标,一个scheme已经在一整套综合的投入testing。 如果您使用代码覆盖率作为您正确性置信度的最佳经验近似值,则应该根据分支覆盖率或类似条件设置标准。

还有很多其他指标(行覆盖率类似于语句覆盖率,但是对于多行语句产生不同的数值结果;例如,条件覆盖率和path覆盖率与分支覆盖率类似,但是反映了可能的排列的更详细的视图你可能遇到的程序执行。)

需要多less百分比?

最后回到原来的问题:如果你设置了代码覆盖标准,那么这个数字应该是多less?

希望现在清楚的是,我们正在讨论一个近似值,所以我们select的任何数字都将是内在的近似值。

一些人可能会select的数字:

  • 100% 。 你可以select这个,因为你想确保一切都经过testing。 这不会让你对testing质量有任何洞察力,但是会告诉你一些质量的testing已经触及了每一个声明(或者分支等)。再一次,这又回到了自信的程度:如果你的覆盖率低于100% ,你知道你的代码的一些子集是未经testing的。
    • 有人可能会认为这很愚蠢,你应该只testing你的代码中非常重要的部分。 我会争辩说,你也应该只维护你的代码中非常重要的部分。 代码覆盖率也可以通过删除未经testing的代码来改善。
  • 99% (或95%,九十年代的其他数字)。适当的情况下,你想传达一个类似于 100%的信心水平,但留下一些余地,不要担心偶尔难以testing的angular落码。
  • 80% 。 我已经看过这个号码几次,并不完全知道它起源于哪里。 我这可能是对80-20规则的一个怪异的盗用行为。 一般来说,这里的意图是显示大部分代码已经过testing。 (是的,51%也是“最多”,但是80%更能反映大多数人的意思 。)这适用于“经过充分testing”不是高优先级的中等情况,不要在低价值的testing上浪费精力),但是你仍然希望拥有一些标准,这已经足够了。

在实践中,我还没有看到80%以下的数字,并且很难想象一个可以设定的情况。 这些标准的作用是增加对正确性的信心,而低于80%的数字不是特别有信心的。 (是的,这是主观的,但是当你设定标准时,这个想法就是做一次主观select,然后进行客观测量。)

其他说明

以上假定正确性是目标。 代码覆盖只是信息; 这可能与其他目标有关。 例如,如果您担心可维护性问题,那么您可能关心的是松耦合,这可以通过可testing性来certificate,而可testing性又可以通过代码覆盖来测量(以某种方式)。 因此,您的代码覆盖率标准为近似“可维护性”的质量提供了经验基础。

85%将是签入标准的一个很好的起点。

我可能会select各种更高的钢筋作为运输标准 – 取决于所testing的子系统/部件的重要性。

如果这是一个完美的世界,100%的代码将被unit testing覆盖。 然而,由于这不是一个完美的世界,这是你有时间的问题。 因此,我build议不要把重点放在特定的比例上,而应该把重点放在关键领域上。 如果你的代码是写得很好的(或者至less是合理的传真),那么应该有几个API暴露给其他代码的关键点。

将您的testing工作集中在这些API上。 确保API是1)有充分的文档logging,2)有写与文档匹配的testing案例。 如果预期的结果与文档不匹配,那么您的代码,文档或testing用例中都有一个错误。 所有这些都是很好的审查。

祝你好运!

对于一个devise良好的系统来说,unit testing从一开始就推动了开发,我认为85%是一个相当低的数字。 devise为可testing的小class不应该难以胜任。

用这样的东西来解决这个问题很容易:

  • 被覆盖的线不等于被testing的逻辑,并且不应该读太多百分比。

没错,但是代码覆盖率还有一些要点。 根据我的经验,如果使用正确,这个指标实际上是非常有用的。 话虽如此,我还没有看到所有的系统,我敢肯定,有很多的代码覆盖分析增加了任何真正的价值。 代码看起来如此不同,可用的testing框架的范围可能会有所不同。

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

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

  • 低水位标志(Low Water Mark,LWM)是被测系统中所见到的最less的未覆盖线条
  • 高水印(HWM)是被测系统的最高代码覆盖率

新代码只能添加,如果我们不超过LWM,我们不低于HWM。 换句话说,代码覆盖率是不允许减less的 ,新代码应该被覆盖。 注意我应该怎么说,而不是必须(下面解释)。

但是,这不就意味着要清理掉已经没有用的老旧的垃圾是不可能的吗? 是的,这就是为什么你必须务实这些事情。 有些情况下,规则必须被打破,但对于你的典型的日常整合,我的经验是这些指标是非常有用的。 他们给出以下两个含义。

  • 可testing的代码被提升。 添加新代码时,您必须尽可能使代码可testing,因为您将不得不尝试使用testing用例来覆盖所有代码。 可testing代码通常是一件好事。

  • 遗留代码的testing覆盖率正在不断增加。 当添加新的代码并且不能用testing用例来覆盖代码时,可以尝试覆盖一些遗留的代码,以避开LWM规则。 这种有时候必要的作弊至less会带来积极的副作用,即遗留代码的覆盖率将会随着时间的推移而增加,使得这些规则看似严格的执行在实践中相当务实。

而且,如果反馈环路太长,在集成过程中设置类似的东西可能是完全不切实际的。

我还想提一下代码覆盖率度量的两个更普遍的好处。

  • 代码覆盖率分析是dynamic代码分析的一部分(而不是静态代码分析,即Lint)。 在dynamic代码分析过程中发现的问题(通过purify系列工具, http ://www-03.ibm.com/software/products/en/rational-purify-family)是类似于未初始化的内存读取(UMR),内存泄漏等。 只有在代码被执行的testing用例覆盖的情况下,才能发现这些问题 。 在testing用例中最难覆盖的代码通常是系统中的exception情况,但是如果您希望系统优雅地失败(即错误跟踪而不是崩溃),您可能想要花费一些精力来覆盖exception情况在dynamic代码分析中也是如此。 如果运气不好,UMR可能导致段错误或更糟。

  • 人们为保持100%的新代码感到自豪,人们以与其他实现问题类似的热情讨论testing问题。 这个函数如何以更可testing的方式编写? 你将如何去覆盖这个exception的情况,等等

而为了完整性,则是否定的。

  • 在一个涉及开发人员众多的大型项目中,每个人都不会成为testing天才。 有些人倾向于使用代码覆盖率度量来certificate代码已经被testing,这是非常不真实的 ,正如在这个问题的许多其他答案中所提到的。 如果使用得当,这是一个可以给你一些好处的度量标准,但是如果它被滥用,它实际上可能导致错误的testing。 除了上面提到的非常有价值的副作用之外,被覆盖的行只显示被testing的系统可以到达那一行以获得一些input数据,并且它可以在没有挂起或崩溃的情况下执行。

一般来说,从我看过的几个工程卓越最佳实践文件中,unit testing新代码的80%是获得最佳回报的关键。 超过CC%,所付出的努力就会产生更less的缺陷。 这是许多大公司使用的最佳实践。

不幸的是,这些结果大部分都是公司内部的,所以没有公开的文献可以指出。

我使用cobertura,无论百分比如何,我都build议保持cobertura-check任务的值保持最新。 至less,不断提高总分和总分支到刚刚低于你目前的覆盖面,但从降低这些值。 还要将Ant构build失败属性绑定到此任务。 如果构build由于缺乏覆盖而失败,则知道有人添加了代码,但尚未对其进行testing。 例:

 <cobertura-check linerate="0" branchrate="0" totallinerate="70" totalbranchrate="90" failureproperty="build.failed" /> 

当我认为我的代码没有经过足够的unit testing,而且我不知道接下来要testing什么,我使用coverage来帮助我决定接下来testing什么。

如果我在unit testing中增加覆盖率 – 我知道这个unit testing值得一提。

这适用于未覆盖的代码,覆盖率为50%或覆盖率为97%。

代码覆盖率只是另一个指标。 本身可能是非常具有误导性的(参见www.thoughtworks.com/insights/blog/are-test-coverage-metrics-overrated )。 因此,您的目标不应该是实现100%的代码覆盖率,而是确保您testing应用程序的所有相关scheme。

如果你已经进行了一段时间的unit testing,我没有理由不接近95%。 但是,至less,我一直在使用80%,即使是新的testing。

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

代码覆盖率很高,但只要您从中获得的好处超过了实现它的成本/努力。

我们一直在努力达到80%的标准,但是我们已经决定放弃这个标准,而更多地专注于我们的testing。 专注于复杂的业务逻辑等,

这个决定是由于我们追逐代码覆盖的时间越来越长,维护现有的unit testing。 我们觉得我们已经达到了从我们的代码覆盖范围中获得的好处被认为比我们为实现这个目标所付出的努力要less的地步。

许多商店不重视testing,所以如果你至less有零点以上的价值升值 – 所以可以说非零不是不坏,因为许多零仍然是零。

在.Net世界中,人们经常以80%的理由引用。 但是他们在解决scheme层面这样说。 我更喜欢在项目级别进行衡量:如果你有Selenium等等,或者手动testing,那么30%对于UI项目来说可能是好的,对于数据层项目来说,20%可能是好的,但对于商业来说,95%以上是可以实现的规则层,如果不是完全必要的话。 因此,整体覆盖率可能是60%,但关键的业务逻辑可能要高得多。

我也听到这个:渴望100%,你会达到80%; 但是希望达到80%,你会达到40%。

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

看看Crap4j 。 这是比直接代码覆盖更复杂的方法。 它将代码覆盖率测量与复杂度测量相结合,然后向您显示目前未testing的复杂代码。

我对这个难题的回答是,你可以testing的代码的100%覆盖率,以及你不能testing的代码的0%覆盖率。

我目前的做法是将我的.py模块分成两个文件夹:app1 /和app2 /,运行unit testing时,计算这两个文件夹的覆盖范围,并在视觉上检查(我必须在某天自动执行)app1具有100% app2的覆盖率为0%。

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

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

我偶尔也会回顾一下app2 /,看看是否可以在那里testing任何代码,如果我可以将它移动到app1 /

现在我不担心总体覆盖率,因为这个数字可能会随着项目规模的不同而变化很大,但通常我已经看到了70%到90%以上。

使用python,我应该能够devise一个烟雾testing,它可以在测量覆盖率时自动运行我的应用程序,并且希望在将烟雾testing与unit testing数据相结合时获得100%的聚合。

从另一个angular度看待覆盖:编写得很好的代码具有清晰的控制stream程,是最容易被阅读的,最容易阅读的,通常是最less的代码。 通过编写清晰易懂的代码,并通过与代码并行编写unit testing,可以得到最好的结果。

在我看来,答案是“这取决于你有多less时间”。 我尽量达到100%,但是如果我没有时间,我不会大惊小怪。

当我编写unit testing时,与开发生产代码时戴的帽子相比,我戴了一顶不同的帽子。 我想想testing的代码声称做什么以及有什么可能打破它的情况。

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

  1. unit testing应该是一个关于我的代码的预期行为的文档forms, 预期的输出给定了一定的input以及它可能抛出的exception,客户可能想要捕捉(我的代码的用户应该知道什么?)

  2. unit testing应该帮助我发现,如果条件我可能还没有想到。 (如何使我的代码稳定和健壮?)

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

这取决于你的应用程序。 例如,某些应用程序主要由不能进行unit testing的GUI代码组成。

我不认为可以有这样的B / W规则。
应审查代码,特别注意关键细节。
但是,如果没有经过testing,它有一个bug!

根据代码的重要性,75%-85%的任何地方都是一个很好的经验法则。 运输代码应该比在房屋公用设施等方面更彻底地进行testing。

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

如果你已经开发了一段时间,并且已经有很多已经实现的代码,并且刚刚意识到你需要考虑代码覆盖率,那么你必须检查你当前的覆盖范围(如果存在的话),然后使用该基线设定每个冲刺的里程碑(或冲刺期间的平均增长),这意味着承担代码债务,同时继续提供最终用户价值(至less根据我的经验,如果您增加了testing,最终用户不关心一点如果他们没有看到新的function)。

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

我认为正确的代码覆盖的最好的症状是unit testing有助于解决的具体问题的数量合理地对应于您创build的unit testing代码的大小。

我认为最重要的是知道覆盖的趋势是随着时间的推移,并了解趋势变化的原因。 无论您认为趋势的变化是好还是坏,取决于您对原因的分析。

我更喜欢使用BDD,它使用自动验收testing,可能的其他集成testing和unit testing的组合。 对我来说,问题是整个自动化testing套件的目标覆盖率应该是多less。

除此之外,答案取决于你的方法,语言,testing和覆盖工具。 在使用Ruby或Python进行TDD时,要保持100%的覆盖率并不难,而且值得这样做。 pipe理100%的覆盖率比90%的覆盖率要容易得多。 也就是说,填补覆盖差距要比填补覆盖差距要容易得多(在进行TDD的时候,覆盖面的差距很less,通常也值得花时间),而不是pipe理一个覆盖范围的清单,由于您不断发现的代码背景而导致的回归。

答案也取决于你的项目的历史。 我只是发现上述在从一开始就pipe理的项目中是可行的。 我已经大大改进了大型遗留项目的覆盖范围,值得这样做,但是我从来没有发现返回并填补每个覆盖范围的空白是不实际的,因为旧的未经testing的代码没有被正确理解,很快。

简短的回答:60-80%

长答案:我认为这完全取决于你的项目的性质。 我通常通过unit testing每一个实际的部分来开始一个项目 通过项目的第一个“发布”,根据您正在进行的编程types,您应该拥有相当不错的基本百分比。 在这一点上,您可以开始“执行”最低代码覆盖率。

直到几天前我们的目标是> 80%,但是在我们使用了大量生成的代码之后,我们并不在乎%的年龄,而是让审稿人对所需的覆盖范围进行调用。

从Testivus发布,我认为答案的上下文应该是第二个程序员。 从实际angular度来说,我们需要参数/目标来争取。 我认为,这可以通过分析代码,我们有架构,function(用户故事),然后拿出一个数字在敏捷过程中“testing”。 根据我在电信领域的经验,我会说60%是一个很好的检查价值。