你如何衡量你的unit testing的质量?

如果您(或您的组织)渴望彻底地testing您的代码,您如何衡量您的努力的成功或质量?

  • 你使用代码覆盖率,你的目标是什么百分比?
  • 你觉得像TDD这样的哲学比衡量指标有更好的影响吗?

我的提示并不是确定本身是否有良好的unit testing的一种方法,但是这是随着时间推移发展一个好的testing套件的一种方法。

每当遇到一个错误,无论是在开发过程中还是其他人的报告,修复它两次。 你首先创build一个重现问题的unit testing。 当你有一个失败的testing,然后你去解决这个问题。

如果问题出现在第一位,这就暗示了关于代码或域的细微之处。 为它添加testing可以确保将来不会再重新引入。

关于这种方法的另一个有趣的方面是,它会帮助你在实际上去之前从更高层次上理解问题,并看看代码的复杂性。

此外,其他人已经提到的testing覆盖率的价值和缺陷为+1。

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

我的经验告诉我,比试图获得100%覆盖率更重要,这不是那么容易,人们应该把重点放在检查关键部分。 但即使如此,你可能会得到误报。

如果可以打破,就应该进行testing。 如果可以testing的话,应该是自动的。

我非常支持TDD,但我不太重视覆盖统计。 对我来说,开发团队在一段开发时间期间会感受到unit testing的成功和有用性,因为testing(a)事先发现错误,(b)使得重构和改变不会退化,(c)帮助充实模块化,分离devise,(四)什么的。

或者,正如马丁·福勒(Martin Fowler)所说的那样,支持unit testing和TDD的轶事性证据是压倒性的,但是你不能测量生产力。 阅读更多在他的bliki在这里: http : //www.martinfowler.com/bliki/CannotMeasureProductivity.html

为了充分确信你的代码,你需要不同级别的testing:单元,集成和function。 我同意上面给出的build议,认为testing应该是自动化的(持续集成),并且unit testing应该覆盖具有各种边界情况数据集的所有分支。 代码覆盖工具(例如Cobertura,Clover,EMMA等)可以识别分支中的漏洞,但不能检测testing数据集的质量。 静态代码分析(如FindBugs,PMD,CPD)可以在代码出现问题之前识别问题区域,并在促进更好的开发实践方面迈出很长的一步。

testing应该尝试复制应用程序将尽可能运行的整体环境。 它应该从最简单的情况(单位)到最复杂的(function性的)。 在一个Web应用程序的情况下,获得一个自动化的过程运行通过各种浏览器的网站的所有用例是必须的,所以像SeleniumRC应该在你的工具包。

然而,软件的存在是为了满足业务需求,所以也有testing需求。 这往往是更多的基于function(networking)testing的手动过程。 实质上,您需要根据规范中的每个要求和相应的functiontesting来构build可追溯性matrix。 随着functiontesting的创build,它们将与一个或多个要求相匹配(例如,以Fredlogin,更新密码的帐户详细信息,再次注销)。 这解决了交付物是否符合业务需求的问题。

总的来说,我会主张一种基于自动化unit testing(JUnit,nUnit等)的风格的testing驱动开发方法。 对于集成testing,我build议有一个testing数据库,每个构build时都会自动填充一个已知的数据集,该数据集说明常见的用例,但允许其他testing构build。 对于functiontesting,您需要某种用户界面机器人(SeleniumRC for Web,Abbot for Swing等)。 在构build过程中可以轻松地收集每个指标的度量标准,并将其显示在CI服务器(例如Hudson)上供所有开发人员查看。

如果衡量testing质量的主要方法是一些自动衡量指标,那么您已经失败了。

度量标准可能会产生误导,并且可以进行游戏。 如果衡量标准是评估质量的主要手段(或者更坏的手段),那么它们将会被游戏化(也许是无意的)。

例如,代码覆盖率是非常具有误导性的,因为100%的代码覆盖率远不及完整的testing覆盖率。 另外,像“80%代码覆盖率”这样的数字在没有上下文的情况下也同样具有误导性。 如果覆盖范围在最复杂的代码中,并且错过了那么简单的代码,那么很容易通过眼睛来validation,那么比覆盖范围相反的方式要好得多。

此外,区分testing的testing域(本质上是function集)和质量是很重要的。 testing质量不是由testing的多less决定的,而是由代码质量不是由特性的清单列表决定的。 testing质量取决于testing在testing中的工作情况。 这实际上是非常难以总结在一个自动化的度量。

下一次你去写一个unit testing,试试这个实验。 查看有多less种不同的编写方式,以使它具有相同的代码覆盖率并testing相同的代码。 看看是否有可能编写一个非常差的testing,以符合这些标准和一个很好的testing。 我想你可能会对结果感到惊讶。

最终,经验和判断是不可替代的。 一个人的眼睛,希望有几个眼睛,需要看testing代码,并决定是否好。

代码覆盖率是testing,因为testing是编程。 它只能告诉你什么时候出现问题,什么时候一切正常。 你应该有100%的代码覆盖率和超越。 代码逻辑的分支应该用几个input值进行testing,充分发挥正常,边缘和angular落的情况。

我通常做TDD,所以我先写testing,这有助于我看到我想如何使用这些对象。

然后,当我写这些类的时候,大部分时候我可以发现一些常见的陷阱(即我所做的假设,例如一个variables是一个特定的types或者一系列的值),当这些错误出现时,我写一个针对该具体情况的具体testing。

除此之外,尽可能的覆盖代码覆盖率(有时不可能达到100%),你或多或less地完成了。 然后,如果将来出现任何错误,只要确保为其编写了一个testing用例,然后在修复时通过。 然后按照正常方式修复。

监控代码覆盖率可能是有用的,但不是把重点放在任意的目标速度(80%,90%,100%?)上,我发现它有助于瞄准一段时间的积极趋势。

我认为unit testing的一些最佳实践是:

  • 他们必须是独立的,即不需要太多的configuration和外部依赖运行。 让testing构build自己的依赖关系,例如运行testing所需的文件和网站。
  • 在修复错误之前使用unit testing来重现错误。 这有助于防止将来再次出现错误。
  • 使用代码覆盖工具来发现任何unit testing未执行的关键代码。
  • 集成unit testing,每晚构build和发布构build。
  • 将testing结果报告和代码覆盖率报告发布到团队中的每个人都可以浏览的网站。 理想情况下,发布应该是自动化的,并且集成到构build系统中。

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

我尝试使用的另一种技术是将代码分成两部分。 我最近在这里博客了。 简短的描述是维护你的生产代码在两套库中,其中一套(希望更大的集合)具有100%的线覆盖率(或更好,如果你可以测量它)和另一套(希望只是less量的代码) 0%的覆盖率,是覆盖率。

你的devise应该允许这个分区。 这应该很容易看到没有涉及的代码。 随着时间的推移,您可能会对如何将代码从较小的集合移动到较大的集合有一些想法。

  • 除了TDD之外,我还发现自己编写了比BDD更合理的testing(例如http://rspec.info/
  • 永远的讨论永远是嘲笑或不嘲笑。 有些嘲讽可能会变得比它正在testing的代码更复杂(通常指的是关注点的分离)。
    • 因此,我喜欢这样一个指标:像每个代码复杂性testing复杂性。 或简化:每行代码的testing行数。