是否存在单元测试对代码有害的情况?

时间:2009-07-27 16:43:53

标签: unit-testing

本网站上的大部分讨论都非常积极地进行单元测试。我是自己单元测试的粉丝。但是,我发现广泛的单元测试带来了自己的挑战。例如,单元测试通常与他们测试的代码紧密耦合,随着测试量的增加,API变化会变得越来越昂贵。

您是否发现了单元测试对代码质量或交付时间有害的真实情况?你是如何处理这些情况的?是否有任何“最佳实践”可以应用于单元测试的设计和实现?

这里有一个相关的问题:Why didn't unit testing work out for your project?

9 个答案:

答案 0 :(得分:4)

通过广泛的单元测试,您将开始发现重构操作更加昂贵,正是出于您所说的原因。

恕我直言,这是一件好事。对于小而廉价的更改,API的昂贵和大的变化应该具有更大的成本。重构不是免费操作,了解对您自己和API的消费者的影响非常重要。单元测试是衡量API变化消耗成本的绝佳标尺。

虽然工具可以解决部分问题。大多数IDE直接或间接(通过插件)支持其代码库中的重构操作。使用这些操作来改变您的单元测试将减轻一些痛苦。

答案 1 :(得分:3)

  

有没有“最佳实践”   可以应用于设计和   实施单元测试?

确保您的单元测试尚未成为集成测试。例如,如果您对类Foo进行单元测试,那么理想情况下,测试只能在

时中断
  1. Foo发生了变化
  2. 或者Foo
  3. 使用的界面发生了变化
  4. 或者域模型发生了变化(通常你会有一些类似“Customer”的类,它们是问题空间的核心,没有抽象空间,因此不会隐藏在接口之后)
  5. 如果您的测试由于任何其他更改而失败,那么它们已经成为集成测试,随着系统变得越来越大,您将遇到麻烦。单元测试应该没有这样的可伸缩性问题,因为它们会测试一个孤立的单元代码。

答案 2 :(得分:2)

我参与的其中一个项目是经过严格的单元测试;我们为20个左右的课程进行了1000多次单元测试。测试代码略多于生产代码。单元测试发现重构操作期间引入了无数错误;它们确实使得更改,扩展功能等变得简单而安全。发布的代码具有非常低的错误率。

为了鼓励自己编写单元测试,我们特意选择让它们“快速而肮脏” - 我们会在制作项目代码时抨击测试,测试很无聊且“不是真正的代码”,所以一旦我们编写了一个行使生产代码功能的程序,我们就完成了,并继续前进。测试代码的唯一标准是它完全运用了生产代码的API。

我们学到的很难的方法是这种方法不能扩展。随着代码的发展,我们发现需要改变对象之间的通信模式,突然间我有600次失败的单元测试!解决这个问题花了我好几天。对于进一步的主要架构重构,这种级别的测试破坏发生了两到三次。在每种情况下,我都不相信我们可以合理地预见到事先需要的代码演变。

故事的寓意是:单元测试代码需要像生产代码一样干净。你无法通过单元测试中的切割和粘贴来逃脱。您需要应用合理的重构,并尽可能使用代理对象将测试与生产代码分离。

当然,所有这些都会增加单元测试的复杂性和成本(并且可能会给您的测试带来错误!),所以这是一个很好的平衡。但我确实认为,“单元测试”的概念是孤立的,并不是它经常被证明的明确和明确的胜利。我的经验是单元测试,就像编程中的其他一切一样,需要小心,而不是一种可以盲目应用的方法。因此,令我惊讶的是,在这样的论坛和文献中,我没有看到更多关于这个主题的讨论。

答案 3 :(得分:1)

过多的误报可能会减慢开发速度,因此测试您实际想要保持不变的内容非常重要。这通常意味着提前编写单元测试以满足要求,然后进行更详细的单元测试,以检测输出中的意外变化。

答案 4 :(得分:1)

主要是在系统开发时没有进行单元测试的情况下,这是事后的想法而不是设计工具。当您使用自动化测试进行开发时,破坏API的可能性会降低。

答案 5 :(得分:1)

我认为你正在考虑修复症状,而不是认识到整个问题。根本问题是真正的API是已发布的接口*,它应该受到与任何编程合同相同的界限:没有变化!您可以添加到API,并将其称为API v2,但您无法返回并更改API v1.0,否则您确实破坏了向后兼容性,这对于API来说几乎总是一件坏事。

(*我不是要指出任何特定的接口技术或语言,接口可能意味着任何来自类声明的东西。)

我建议测试驱动开发方法首先有助于防止这些问题。使用TDD,您在编写测试时会“感觉”接口的尴尬,并且您将被迫在此过程的早期修复这些接口,而不是等到您编写了一千个测试之后。

测试驱动开发的一个主要好处是它可以为您提供有关类/接口的编程使用的即时反馈。编写测试的行为是对您的设计的测试,而运行测试的行为则是对您行为的测试。如果为特定方法编写测试很困难或笨拙,那么该方法可能会被错误地使用,这意味着它是一个弱设计,应该快速重构。

答案 6 :(得分:0)

如果您确定您的代码不会被重复使用,则不需要保留,您的项目很简单且非常短期;那么你不应该进行单元测试。

单元测试有助于促进更改和维护。他们确实在交货时增加了一点时间,但是在中期/长期支付。如果没有中期/长期,则可能没有必要,只需进行手动测试。

但是,但所有这一切都不太可能。所以它们仍然是一种趋势:)

此外,有时候可能需要做出必要的商业决策,以减少测试时间,以便更快地进行紧急交付(以后需要支付利息)

答案 7 :(得分:0)

是的,有些情况下,单元测试可能会对代码质量和交付时间产生不利影响。如果你创建了太多的单元测试,你的代码将会被界面破坏,你的代码质量将会受到影响。抽象很棒,但你可以拥有太多的东西。

如果您的写作单元测试的原型或系统很有可能发生重大变化,您的单元测试将对交付时间产生影响。在这些情况下,通常更好地编写接近测试,接近端到端的测试。

答案 8 :(得分:0)

慢速单元测试通常会对开发产生不利影响。当单元测试成为需要访问Web服务或数据库的集成测试时,通常会发生这种情况。如果您的单元测试套件需要一个多小时才能运行,通常您会发现自己和您的团队在那个小时内基本上处于瘫痪状态,等待单元测试是否通过(因为您不想继续构建破碎的基础)。

话虽如此,我认为的好处超过了除了最人为的案例之外的所有缺点。