您如何衡量单元测试的质量?

时间:2008-11-04 17:57:23

标签: unit-testing testing tdd

如果您(或您的组织)希望对您的代码进行彻底的单元测试,您如何衡量您的成功或质量?

  • 您是否使用代码覆盖率,您的目标是多少?
  • 您是否发现像TDD这样的哲学比指标有更好的影响?

13 个答案:

答案 0 :(得分:34)

我的提示不是确定您是否拥有良好的单元测试本身的方法,但它是一种随着时间的推移发展出良好测试套件的方法。

无论何时遇到错误,无论是在开发中还是由其他人报告,都要修复两次。首先创建一个单元测试来重现问题。当你有一个失败的测试,然后你去解决问题。

如果首先出现问题,那就是关于代码或域名的微妙暗示。为它添加测试可以确保将来不再重新引入它。

这种方法的另一个有趣的方面是,它可以帮助您在实际查看代码的复杂性之前从更高级别了解问题。

此外,其他人已经提到过测试覆盖率的价值和陷阱+1。

答案 1 :(得分:12)

代码覆盖率是一个有用的指标,但应谨慎使用。有些人采用代码覆盖,特别是涵盖的百分比,有点太认真,并将其视为良好单元测试的指标。

我的经验告诉我,比试图获得100%覆盖更重要,这并不容易,人们应该专注于检查关键部分。但即便如此,你也可能会得到误报。

答案 2 :(得分:9)

我非常支持TDD,但我不太重视报道统计数据。对我来说,开发团队在开发时间段内感受到单元测试的成功和实用性,因为测试(a)预先发现错误,(b)实现重构和更改而不会回归,(c)帮助充实模块化,解耦设计,(d)和诸如此类的。

或者,正如Martin Fowler所说,支持单元测试和TDD的轶事证据是压倒性的,但你无法衡量生产力。在这里阅读更多关于他的bliki:http://www.martinfowler.com/bliki/CannotMeasureProductivity.html

答案 3 :(得分:8)

如果它可能破裂,应该进行测试。如果可以测试,它应该是自动化的。

答案 4 :(得分:8)

为了充分衡量您的代码,您需要不同级别的测试:单元,集成和功能。我同意上面给出的建议,即测试应该是自动化的(持续集成),并且单元测试应该涵盖具有各种边缘案例数据集的所有分支。代码覆盖工具(例如Cobertura,Clover,EMMA等)可以识别分支中的漏洞,但不能识别测试数据集的质量。静态代码分析(如FindBugs,PMD,CPD)可以在代码成为问题之前识别代码中的问题区域,并大大促进更好的开发实践。

测试应尝试尽可能复制应用程序将运行的整体环境。它应该从最简单的情况(单位)开始到最复杂的(功能)。对于Web应用程序,必须使用各种浏览器来运行遍历网站所有用例的自动化过程,因此SeleniumRC应该在您的工具包中。

但是,软件的存在是为了满足业务需求,因此也有针对需求的测试。这往往更像是基于功能(网络)测试的手动过程。基本上,您需要针对规范中的每个需求和相应的功能测试构建可跟踪性矩阵。在创建功能测试时,它们会与一个或多个要求相匹配(例如,登录为Fred,更新密码的帐户详细信息,再次注销)。这解决了交付物是否符合业务需求的问题。

总的来说,我会提倡基于某种自动化单元测试(JUnit,nUnit等)的测试驱动开发方法。对于集成测试,我建议使用一个测试数据库,该数据库在每个构建时使用已知数据集自动填充,该数据集说明了常见用例,但允许构建其他测试。对于功能测试,您需要某种用户界面机器人(用于Web的SeleniumRC,用于Swing的Abbot等)。可以在构建过程中轻松收集每个度量标准,并在CI服务器(例如Hudson)上显示,供所有开发人员查看。

答案 5 :(得分:6)

如果您测量测试质量的主要方法是某种自动指标,那么您已经失败了。

指标可能会产生误导,并且可以进行游戏。如果度量标准是判断质量的主要(或者更糟糕的是),那么它们将被游戏(可能是无意的)。

例如,代码覆盖率极具误导性,因为100%的代码覆盖率远远不及完整的测试覆盖率。此外,像“80%代码覆盖率”这样的数字在没有上下文的情况下也会产生误导。如果这个覆盖范围是最复杂的代码,并且只是错过了那么简单的代码,那么很容易通过眼睛进行验证,那么这种情况要好于覆盖范围相反的情况。

此外,区分测试的测试域(基本上是功能集)和质量也很重要。测试质量不取决于测试的程度,因为代码质量不是由特征列表决定的。测试质量取决于测试在测试中的表现。实际上很难总结自动化指标。

下次您去编写单元测试时,请尝试此实验。查看有多少种不同的编写方式,使其具有相同的代码覆盖率并测试相同的代码。看看是否有可能编写一个符合这些标准的非常差的测试,以及一个非常好的测试。我想你可能会对结果感到惊讶。

最终,没有经验和判断力的替代品。人眼,希望是几只眼睛,需要查看测试代码并确定它是否好。

答案 6 :(得分:5)

代码覆盖是测试,因为测试是编程。它只能告诉你何时出现问题,它无法告诉你何时一切正常。您应该拥有100%的代码覆盖率。应使用多个输入值测试代码逻辑分支,完全处理正常,边缘和极点情况。

答案 7 :(得分:5)

我通常做TDD,所以我先写测试,这有助于我了解我希望如何使用这些对象。

然后,当我写这些课程时,在大多数情况下,我可以发现常见的陷阱(即我正在做的假设,例如变量属于特定类型或值范围),当这些出现时我为这个具体案例写了一个特定的测试。

除此之外,并且尽可能地获得代码覆盖率(有时候不可能获得100%),您或多或少都会完成。然后,如果将来出现任何错误,您只需确保为其编写一个首先公开它的测试用例,并在修复时通过。然后按照正常情况修复。

答案 8 :(得分:3)

监控代码覆盖率可能很有用,但我没有关注任意目标利率(80%,90%,100%?),我发现随着时间的推移,积极趋势是有用的。

答案 9 :(得分:2)

我认为单元测试的一些最佳实践是:

  • 它们必须是自包含的,即不需要太多配置和外部依赖项来运行。让测试构建自己的依赖项,例如运行测试所需的文件和网站。
  • 使用单元测试在修复之前重现错误。这有助于防止错误在未来再次出现。
  • 使用代码覆盖工具来发现任何单元测试未执行的关键代码。
  • 将单元测试与夜间构建和发布版本集成。
  • 将测试结果报告和代码覆盖率报告发布到网站中的每个人都可以浏览的网站。理想情况下,发布应自动化并集成到构建系统中。

除非您开发关键任务软件,否则不要期望达到100%的代码覆盖率。达到这个水平可能是非常昂贵的,而且大多数项目都不值得付出努力。

答案 10 :(得分:1)

我尝试使用的另一种技术是将代码分为两部分。我最近在博客上写了here。简短的描述是将您的生产代码保存在两组库中,其中一组(希望是更大的组)具有100%的线覆盖率(或者如果可以测量它更好),另一组(希望是少量代码)具有0%覆盖率,是零%覆盖率。

您的设计应允许此分区。这样可以很容易地看到未涵盖的代码。随着时间的推移,您可能会想到如何将代码从较小的集合移动到较大的集合。

答案 11 :(得分:1)

突变测试的概念似乎很有前途,可以衡量(测试?)单元测试的质量。变异测试基本上意味着对您的生产代码进行小的“突变”,然后查看是否有任何单元测试失败。小突变通常意味着将and更改为or<更改为<=。如果一个或多个单元测试失败,则意味着“突变体”被捕获。如果突变体存活在您的单元测试套件中,则意味着您错过了测试。当我将突变测试应用于具有100%线路和分支覆盖的代码时,它通常会找到一些我错过测试的位置。

有关概念的说明和工具链接,请参阅https://en.wikipedia.org/wiki/Mutation_testing

答案 12 :(得分:0)

  • 除了TDD,我发现自从BDD以来我写了更多理智的测试(例如http://rspec.info/
  • 永远的讨论总是嘲笑或不嘲笑。有些模拟可能比它测试的代码更复杂(这通常表明关注点分离不当)。
    • 因此,我喜欢使用以下指标的想法:测试复杂性 每代码复杂性。或简化:每行代码的测试行数。