测试是否比正在测试的实际代码大?对于我正在测试的每行代码,我通常在单元测试中有2-3行。这最终导致花费大量时间只需键入测试(模拟,模拟和模拟更多)。
节省时间在哪里?你有没有避免测试代码是否是微不足道的?我的大部分方法都不到10行,测试每一个方法需要花费很多时间,如你所见,我开始质疑大部分测试的编写。
我不是在提倡不进行单元测试,我喜欢它。只想看看人们在编写测试之前考虑的因素。它们是有代价的(就时间而言是金钱),所以必须以某种方式评估这个成本。如果有的话,您如何估算单元测试所带来的节省?
答案 0 :(得分:16)
您可能正在测试错误的东西 - 您不应该对代码中的每个方法进行不同的测试。
您可能有太多测试,因为您测试实现而不是功能 - 尝试测试完成测试的方法。
例如,如果您的客户有权获得每笔订单的折扣 - 使用正确的数据创建客户并为该客户创建订单,然后确保最终价格正确。这样你就可以测试业务逻辑,而不是内部如何完成。
另一个原因是,如果你需要初始化需要大量代码的困难对象尝试使用伪造/模拟,那么大型测试就是缺少隔离(a.k.a模拟)。
最后,如果您有复杂的测试,那可能就是一种气味 - 如果您需要编写大量代码来测试一个简单的功能,那么可能意味着您的代码紧密耦合且您的API不够清晰。
答案 1 :(得分:6)
单元测试代码应遵循与生产代码相同的最佳实践。如果您有那么多的单元测试代码,它会有一种违反DRY原则的气味。
重构单元测试以使用Test Utility Methods应有助于减少整体单元测试占用空间。
答案 2 :(得分:2)
过多的测试代码可能意味着正在测试的实际代码不是为可测试性而设计的。谷歌开发人员有一个很棒的guide on testability试图解决这个问题。
设计糟糕的代码意味着大量的测试代码只有一个原因:使实际代码可测试。通过良好的设计,测试可以更多地关注重要的事情。
答案 3 :(得分:1)
好吧,
这是一种权衡方案,其中更多测试可确保稳定性。通过稳定性,它不仅意味着被测代码更加无错误且万无一失,它可以保证程序在未来的任何情况下都不会破坏。无论你如何疯狂地将参数传递给方法,代码块都会正确返回(当然需要适当的错误信息)。
更重要的是,您甚至可以在知道被测方法的内部操作之前编写单元测试用例。这就像一个黑盒子的场景,你将首先完成编写测试用例,然后开始编码。重要的优点是通过并行运行测试用例,开发工作将在更少的迭代中变得无错误。
测试代码的大小根本不重要。重要的是您的单元测试的全面性和覆盖范围。它是仅仅测试同名还是一个处理所有可能情况的严重测试用例。
答案 4 :(得分:1)
测试应该是找到适当的平衡,这取决于许多不同的因素,例如:
我通常只为“公共API”编写测试,因此只隐式测试用于提供公共功能的任何程序集内部类。但随着您对可靠性和可重复性的需求增加,您还应该添加其他测试。
答案 5 :(得分:1)
非常有效且好的问题。我需要时遵循简单的原则。
虽然所有这些都需要相当长的时间,但只要我们记住输出应该是好的并且没有bug,我们坚持上面的事情就好了。
答案 6 :(得分:1)
这种情况经常发生。找出它是好还是坏的关键是找出测试更大的原因。
有时它们更大只是因为需要覆盖很多测试用例,或者规范很复杂,但实现规范的代码并不那么冗长。
另外,请考虑消除错误所需的时间。如果单元测试可以防止某些错误发生,那些需要花费更多时间进行调试和修复的错误,你会认为TDD会让你的开发时间更长吗?
答案 7 :(得分:1)
答案 8 :(得分:0)
是的,很可能会发现测试的loc比你测试的实际代码多,但在考虑调试代码时节省的时间是完全值得的。
每次进行更改时,您都不必手动测试整个应用程序/库,而是可以依赖于您的测试套件,如果失败,您可以获得更准确的信息,而不是“它不起作用”。
关于避免测试:如果你没有测试代码的某些部分,那么你实际上正在破坏测试的整个概念和目的,那么测试实际上是无用的。
但是,你不会测试你没写过的东西。也就是说,您假设外部库正常工作,并且生成的getter / setter方法(如果您的语言支持这些方法)也不必进行测试。假设在为变量赋值时不会失败,这是非常安全的。答案 9 :(得分:0)
当我编写测试或做TDD时,其中一个指导我的事情(顺便提一下,我从对SO的一个问题的答案中得到的答案)就是你不需要对你的设计/架构一样小心。尽可能多地测试您的实际代码。只要他们正确地完成工作,测试可能有点脏和次优(代码设计明智)。像所有关于设计的建议一样,它应该明智地应用,并且没有经验可以替代。
答案 10 :(得分:0)
是的,这很正常。测试代码比生产代码长,这不是问题。
也许你的测试代码可能比它更短,也许不是,但无论如何你不希望测试代码“聪明”,我认为在写完第一篇文章之后你就不会除非绝对必要,否则我想将测试代码重构为常见事物。例如,如果您对过去的错误进行了回归测试,那么除非您更改测试中的公共接口,否则请勿触摸该测试代码。永远。如果你这样做,你只需要从错误修复之前提取一些古老版本的实现,以证明新的回归测试仍然能够完成它的工作。浪费时间。如果您修改代码的唯一时间是让它“更容易维护”,那么您只需创建繁忙的工作。
添加新测试通常比用新测试替换旧测试更好,即使您最终会进行重复测试。你冒着错误而没有任何好处。例外情况是,如果您的测试运行时间太长,那么您希望避免重复,但即使这样做也可以通过将测试分成“核心测试”和“完整测试”来完成,并运行所有旧的可能重复项不太经常。
答案 11 :(得分:0)
在我的TDD实践中,我倾向于看到更大的测试(在LOC中)测试更接近系统集成点的类,即数据库访问类,Web服务类和认证类。
关于这些单元测试的有趣之处在于,即使在我编写它们之后,我仍然对这些类是否工作导致我使用数据库,Web服务或身份验证服务编写集成测试感到不安。只有在建立自动化集成测试之后,我才能继续前进。
集成测试通常比他们各自的单元测试要短得多,并为我和团队中的其他开发人员做更多工作来证明系统的这一部分能够正常工作。
-HOWEVER -
自动集成测试伴随着他们自己的恶意,包括处理更大的测试运行时,设置和拆除外部资源以及提供测试数据。
在一天结束时,我总是对包含自动化集成测试感到满意,但几乎总是觉得这些“集成”类的单元测试很多工作都没有太大的回报。
答案 12 :(得分:0)
测试2-3倍大不正常。
在测试中使用辅助类/方法。
限制测试范围。
有效使用测试夹具。
有效地使用测试拆卸。
有效使用单元测试框架。
你将不再有这样的测试了。