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

时间:2008-09-18 04:25:40

标签: unit-testing code-coverage code-metrics

如果要为单元测试规定最小百分比代码覆盖率,甚至可能作为提交到存储库的要求,它会是什么?

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

30 个答案:

答案 0 :(得分:1265)

Alberto Savoia的这篇散文正好回答了这个问题(以一种非常有趣的方式解决了这个问题!):

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

  

Testivus On Test Coverage

     一天早上,一位程序员问道   伟大的主人:

     

“我准备写一些单元测试了。我应该瞄准什么代码覆盖   为?”

     

大师回答说:

     

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

     程序员笑了笑,鞠躬,然后   左

     

...

     

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

     

大师指着一壶   沸水说:

     

“我应该在那个锅里放几粒米饭?”

     

程序员看起来很困惑,   回答:

     

“我怎么可能告诉你?这取决于你需要多少人   饲料,它们有多饿,还有什么   你正在吃的食物,多少米饭   你有空,等等。“

     

“没错,”大师说。

     

第二个程序员微笑,鞠躬,   然后离开了。

     

...

     

一天结束时,第三个   程序员来了,问了同样的问题   关于代码覆盖率的问题。

     

“百分之八十也不少!”主人用严厉的声音回答道,   把拳头砸在桌子上。

     

第三个程序员微笑,鞠躬,   然后离开了。

     

...

     

在这最后的回复之后,一个年轻人   学徒接近了伟大的   主:

     

“大师,今天我无意中听到你回答同样的问题   代码覆盖率有三种不同   答案。为什么?”

     

大师从他的身上站了起来   椅:

     

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

     

他们用杯子装满后   吸烟热绿茶,很棒   大师开始回答:

     

“第一个程序员是新手,刚刚开始测试。   现在他有很多代码,没有   试验。他还有很长的路要走;   此时专注于代码覆盖   会令人沮丧而且毫无用处。   他最好习惯   编写并运行一些测试。他可以   后来担心报道。“

     另一方面,第二个程序员非常有经验   在编程和测试。当我   回答问她有多少谷物   米饭,我应该放入锅中,我   帮助她意识到了数量   必要的测试取决于一个数字   因素,她知道那些   因素比我好 - 这是她   毕竟是代码。没有单身,   简单,回答,她足够聪明   处理真相并与之合作   该“。

     

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

     

这位伟大的大师笑得很开心   他的肚子响亮,证明他   喝的不仅仅是绿茶,   上下颠倒。

     

“第三个程序员只想要简单的答案 - 即使有   没有简单的答案......然后没有   无论如何,请跟着他们。“

     

年轻的学徒和灰白的   伟大的大师喝完了他们的   沉思的沉默中的茶。

答案 1 :(得分:80)

如果100%覆盖率是您的目标(而不是对所有功能进行100%测试),则代码覆盖率是一种误导性指标。

  • 你可以通过一次击中所有线来获得100%。但是,您仍然可能错过测试特定序列(逻辑路径),其中这些行被命中。
  • 您无法获得100%但仍测试了所有80%/ freq使用的代码路径。测试每个'抛出ExceptionTypeX'或类似的防御性编程守卫你测试的是'很高兴'不是'必须拥有'

因此,请相信自己或您的开发人员要彻底,并通过他们的代码覆盖每条路径。务实,不要追逐神奇的100%报道。如果您使用TDD代码,则应获得90%以上的奖金。使用代码覆盖来突出显示您错过的代码块(如果您使用TDD,则不应该发生..因为您只编写代码以进行测试通过。没有合作伙伴测试,代码就不会存在。)

答案 2 :(得分:51)

代码覆盖率很高,但功能覆盖率更高。我不相信我写的每一行。但我确实相信我想要提供的所有功能的100%测试覆盖率(即使是我自己带来的超酷功能,也没有在会议期间讨论过。)

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

答案 3 :(得分:45)

接受的答案很重要 - 没有一个数字作为每个项目的标准都有意义。有些项目不需要这样的标准。在我看来,接受的答案不足之处在于描述如何为特定项目做出决定。

我会这样做。我不是测试工程专家,很乐意看到更明智的答案。

何时设置代码覆盖率要求

首先,您为什么要首先强加这样的标准?一般来说,当你想在你的过程中引入经验信心时。我的意思是什么"经验信心"?那么,真正的目标正确性。对于大多数软件,我们无法在所有输入中知道这一点,因此我们决定说代码经过充分测试。这是更容易理解的,但仍然是一个主观标准:无论你是否遇到它,总是可以辩论。这些辩论是有用的,应该发生,但它们也暴露了不确定性。

代码覆盖率是一种客观衡量标准:一旦您看到您的覆盖率报告,就没有关于标准是否有用的歧​​义。它证明是正确的吗?完全没有,但它与代码的良好测试有明确的关系,这反过来又是我们提高其正确性信心的最佳方式。代码覆盖率是我们关心的不可估量的质量的可测量近似值。

具有经验标准的某些具体案例可以增加价值:

  • 满足利益相关者的需求。对于许多项目,有许多对软件质量感兴趣的参与者可能不参与软件的日常开发(经理,技术主管)等等。说'我们要写出我们真正需要的所有测试"并不令人信服:他们要么需要完全信任,要么通过持续的密切监督来验证(假设他们甚至有技术理解这样做。)提供可衡量的标准并解释他们如何合理地接近实际目标更好。
  • 规范团队行为。除了利益相关者之外,如果您正在组建一个多人编写代码和测试的团队,那么对于符合条件的人来说,存在模糊性的空间。 "您的所有同事对于什么级别的测试足够好有同样的想法吗?可能不是。你如何调和这个?找到一个您可以同意的指标,并将其作为合理的近似值接受。这对于大型团队尤其(但并非唯一)有用,例如,潜在客户可能无法直接监督初级开发人员。信任网络也很重要,但如果没有客观的衡量标准,即使每个人都善意地行事,集体行为也很容易变得不一致。
  • 保持诚实。即使您是项目的唯一开发者和唯一的利益相关者,您也可能对软件有一定的品质。您可以使用代码覆盖率作为合理的近似值,让机器为您量身定做,而不是对软件的测试结果进行持续的主观评估(这需要工作)。

使用哪些指标

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

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

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

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

需要的百分比

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

希望在这一点上我们很清楚我们正在谈论一个近似的开头,所以我们选择的任何数字都将是固有的近似值。

有人可能选择的一些数字:

  • 100%即可。您可以选择此选项,因为您希望确保所有内容都经过测试。这并没有给你任何关于测试质量的见解,但确实告诉你一些质量的测试已触及每个声明(或分支等)。再次,这回到了信心程度:如果你的覆盖范围低于100%,您知道您的代码的某些子集未经测试。
    • 有些人可能认为这很愚蠢,你应该只测试代码中非常重要的部分。我认为你应该只维护代码中非常重要的部分。通过删除未经测试的代码也可以改善代码覆盖率。
  • 99%(或95%,九十年代以来的其他数字。)适用于您希望将相似的信心水平传达到100%的情况,但留下一些余地,不用担心偶尔难以测试的代码角落。
  • 80%即可。我已经看过几次这个号码,并且完全不知道它的来源。我认为这可能是对80-20规则的一种奇怪的挪用;通常,这里的目的是表明您的代码的大多数已经过测试。 (是的,51%也是"大多数",但80%更能反映大多数人意味着什么。)这适用于中间地区的情况,其中&# 34;以及测试"不是一个高优先级(你不想浪费在低价值测试上的努力),但是你仍然希望有一些标准,这是一个优先事项。

在实践中我没有看到低于80%的数字,并且很难想象一个人会设置它们的情况。这些标准的作用是增加对正确性的信心,低于80%的数字并不特别有信心。 (是的,这是主观的,但同样,这个想法是在你设定标准时做出一次主观选择,然后再使用客观测量。)

其他说明

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

答案 4 :(得分:23)

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

基本流程是:

  1. 我编写测试来练习我能想到的所有功能和边缘情况(通常使用文档)。
  2. 我运行代码覆盖率工具
  3. 我检查未覆盖的任何线路或路径以及我认为不重要或无法到达的任何线路或路径(由于防御性编程)我标记为不计算
  4. 如果没有提到这些边缘情况,我会编写新的测试来覆盖缺失的行并改进文档。
  5. 这样一来,如果我和我的合作者在未来添加新代码或更改测试,有一条明确的线条告诉我们,如果我们错过了重要的事情 - 覆盖率降至100%以下。但是,它还提供了处理不同测试优先级的灵活性。

答案 5 :(得分:19)

我还有另外一个关于我想分享的测试报道的传感器。

我们有一个庞大的项目,其中,通过推特,我注意到,with 700 unit tests, we only have 20% code coverage

Scott Hanselman回复了words of wisdom

  

是正确的20%吗?是20%吗   代表您的用户的代码   打得最多?您可以再添加50个   测试,只增加2%。

再次,它回到我的Testivus on Code Coverage答案。你应该在锅里放多少米饭?这取决于。

答案 6 :(得分:7)

如果这是一个完美的世界,100%的代码将由单元测试覆盖。然而,由于这不是一个完美的世界,这是你有时间的问题。因此,我建议减少对特定百分比的关注,并更多地关注关键领域。如果您的代码编写得很好(或至少是合理的传真),那么API应该有几个关键点,其中API会暴露给其他代码。

将您的测试工作重点放在这些API上。确保API 1)记录良好,2)编写与文档匹配的测试用例。如果预期结果与文档不匹配,那么您的代码,文档或测试用例中都存在错误。所有这些都很好的审查。

祝你好运!

答案 7 :(得分:7)

对于一个设计良好的系统,单元测试从一开始就推动了开发,我认为85%是一个非常低的数字。设计为可测试的小班不应该难以覆盖。

通过以下方式解决这个问题很容易:

  • 涵盖的行不等于测试逻辑,并且不应过多地读取百分比。

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

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

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

  • 低水位线(LWM),是测试系统中有史以来未覆盖线路的最低数量
  • 高水位线(HWM),是测试系统中有史以来最高的代码覆盖百分比

只有在我们没有超越LWM并且我们不低于HWM时才能添加新代码。换句话说,代码覆盖率不允许减少,应该涵盖新代码。请注意我的说法应该而不是必须(在下面解释)。

但这并不意味着不可能清除那些你再也没用过的旧的经过严格测试的垃圾了吗?是的,这就是为什么你必须对这些事情务实。在某些情况下,规则必须被打破,但对于典型的日常集成,我体验到这些指标非常有用。它们给出了以下两个含义。

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

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

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

我还想提一下代码覆盖率指标的两个更广泛的好处。

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

  • 人们为保持100%的新代码而感到自豪,人们讨论测试问题的热情与其他实现问题类似。如何以更可测试的方式编写此函数?你会如何试图掩盖这种异常情况等等。

负面,完整。

  • 在一个涉及许多开发人员的大型项目中,每个人都不会确定是一个测试天才。 有些人倾向于使用代码覆盖率指标作为代码测试的证据,这远非事实,正如此问题的许多其他答案中所提到的那样。如果使用得当,它是一个可以给你一些好处的指标,但如果它被滥用,它实际上可能导致不好的测试。除了上面提到的非常有价值的副作用之外,覆盖线只显示被测系统可以达到某些输入数据的那一行,并且它可以在不挂起或崩溃的情况下执行。

答案 8 :(得分:5)

许多商店都没有进行价值测试,所以如果你的价值高于零,至少会有一些价值升值 - 所以可以说非零是不好的,因为许多商店仍然为零。

在.Net世界,人们经常引用80%作为推理。但是他们在解决方案层面说这个。我更倾向于在项目级别进行测量:如果您已经获得Selenium等或者手动测试,那么对于UI项目来说30%可能是好的,数据层项目的20%可能没问题,但95%+可能是完全可以实现的。业务规则层,如果不是完全必要的话。因此,总体覆盖率可能是60%,但关键业务逻辑可能要高得多。

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

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

答案 9 :(得分:5)

85%将是签入标准的良好起点。

我可能会根据运输标准选择各种更高的标准 - 取决于所测试的子系统/组件的重要性。

答案 10 :(得分:4)

代码覆盖率只是另一个指标。就其本身而言,它可能会产生误导(见www.thoughtworks.com/insights/blog/are-test-coverage-metrics-overrated)。因此,您的目标不应该是实现100%的代码覆盖率,而是确保您测试应用程序的所有相关方案。

答案 11 :(得分:4)

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

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

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

答案 12 :(得分:4)

我使用cobertura,无论百分比如何,我都建议保持cobertura-check任务中的值保持最新状态。至少,将totallinerate和totalbranchrate提高到恰好低于当前的覆盖范围,但永远不会降低这些值。还要将Ant构建失败属性与此任务联系起来。如果构建因缺少覆盖而失败,则您知道有人添加了代码但尚未对其进行测试。例如:

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

答案 13 :(得分:3)

如果您在相当长的时间内进行单元测试,我认为没有理由不接近95%+。但是,至少,即使刚接触测试,我也总是使用80%。

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

答案 14 :(得分:3)

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

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

答案 15 :(得分:3)

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

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

由于我们花费了大量时间来追逐代码覆盖率并维持现有的单元测试,因此做出了这一决定。我们觉得我们已经达到了从代码覆盖中获得的好处被认为低于我们为实现它而付出的努力的程度。

答案 16 :(得分:2)

我更喜欢做BDD,它使用自动验收测试,可能还有其他集成测试和单元测试的组合。对我而言,问题在于整个自动化测试套件的目标覆盖范围应该是什么。

除此之外,答案取决于您的方法,语言,测试和覆盖工具。在Ruby或Python中进行TDD时,保持100%的覆盖率并不难,值得这样做。 管理100%覆盖率要比90%覆盖率更容易。也就是说,填充覆盖率差距会更容易(并且在进行TDD覆盖时)差距很小,通常值得花时间)而不是管理一个覆盖差距列表,由于你不断发现的代码背景,你已经无法覆盖并错过覆盖率回归。

答案还取决于项目的历史。我只发现上述内容在从一开始就以这种方式管理的项目中是实用的。我已经大大改善了大型遗留项目的覆盖范围,并且值得这样做,但是我从来没有发现返回并填补每个覆盖范围的实际情况,因为旧的未经测试的代码不是很好理解,足以正确而迅速地做到这一点。

答案 17 :(得分:2)

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

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

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

  1. 单元测试应该是关于我的代码的预期行为的文档形式,即。给定一定输入的预期输出以及客户可能想要捕获的异常(我的代码的用户应该知道什么?)

  2. 单元测试应该帮助我发现我可能尚未想到的条件。 (如何使我的代码稳定且健壮?)

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

答案 18 :(得分:2)

我对这个难题的回答是对你可以测试的代码有100%的线覆盖率,你无法测试代码的0%线覆盖率。

我目前在Python中的做法是将我的.py模块分成两个文件夹:app1 /和app2 /,当运行单元测试时,计算这两个文件夹的覆盖范围并进行目视检查(我必须自动化有一天)app1的覆盖率为100%,app2的覆盖率为0%。

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

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

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

现在我并不太担心总体覆盖率,因为根据项目的规模,这可能会有很大差异,但一般来说,我看到70%到90%以上。

使用python,我应该能够设计一个烟雾测试,它可以在测量覆盖范围时自动运行我的应用程序,并希望在将烟雾测试与单位测试数据结合时获得100%的总体响应。

答案 19 :(得分:2)

从另一个角度查看覆盖:具有清晰控制流的编写良好的代码是最容易覆盖的,最容易阅读的,通常是最少的错误代码。通过编写清晰易懂的代码,并通过与代码并行编写单元测试,您可以获得最佳结果恕我直言。

答案 20 :(得分:2)

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

答案 21 :(得分:1)

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

答案 22 :(得分:1)

我认为正确代码覆盖的最佳症状是单元测试有助于修复的具体问题数量合理地对应于您创建的单元测试代码的大小。

答案 23 :(得分:1)

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

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

根据你的域名,以95%的比率进行投篮并不是不合理的,但我不得不平均说你将会看到85%到90%的平均情况。

答案 24 :(得分:1)

根据代码的重要性,75%-85%的任何地方都是一个很好的经验法则。 运输代码绝对应该比家庭公用事业等更彻底地测试。

答案 25 :(得分:1)

简答:60-80%

答案很长: 我认为这完全取决于项目的性质。我通常通过对每个实际部件进行单元测试来启动项目。通过项目的第一个“发布”,您应该根据您正在进行的编程类型获得相当不错的基本百分比。此时,您可以开始“强制执行”最小代码覆盖率。

答案 26 :(得分:1)

我认为不存在这样的B / W规则 应审查代码,特别注意关键细节 但是,如果它还没有经过测试,它就有一个错误!

答案 27 :(得分:1)

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

答案 28 :(得分:0)

从Testivus帖子中我认为答案语境应该是第二个程序员。 从实际的角度说这个,我们需要争取参数/目标。 我认为,通过分析我们拥有架构,功能(用户故事)的代码,然后提出一个数字,可以在敏捷过程中对此进行“测试”。根据我在电信领域的经验,我会说60%是值得检查的。

答案 29 :(得分:0)

我们的目标是> 80%,直到几天前,但在我们使用了大量生成代码之后,我们并不关心%年龄,而是让审核人员接听所需的覆盖范围。