编写“单元可测试”代码?

时间:2009-06-17 14:38:44

标签: unit-testing language-agnostic automated-tests

您使用什么样的做法来使您的代码更适合单元测试?

19 个答案:

答案 0 :(得分:54)

  • TDD - 首先编写测试,强制 你要考虑可测试性和 帮助编写实际的代码 需要,而不是你的想法 需要

  • 重构接口 - 制作 嘲笑更容易

  • 公共方法虚拟,如果不使用 接口 - 使模拟更容易

  • 依赖注入 - 进行模拟 更容易

  • 更小,更有针对性的方法 - 测试更集中,更容易 写

  • 避免使用静态类

  • 避免单身,除非在哪里 必要

  • 避免密封课程

答案 1 :(得分:13)

依赖注入似乎有所帮助。

答案 2 :(得分:10)

首先编写测试 - 这样,测试就可以推动您的设计。

答案 3 :(得分:7)

  1. 使用TDD
  2. 编写代码时,尽可能利用依赖注入
  3. 编程到接口,而不是具体的类,因此您可以替换模拟实现。

答案 4 :(得分:7)

确保所有课程都遵循Single Responsibility Principle。单一责任意味着每个班级应该只有一个责任。这使得单元测试变得更加容易。

答案 5 :(得分:5)

编写测试时(与任何其他软件任务一样)不要重复自己(DRY原则)。如果您的测试数据对多个测试有用,那么将它放在两个测试都可以使用的地方。不要将代码复制到两个测试中。我知道这似乎很明显,但我发现它一直都在发生。

答案 6 :(得分:4)

最简单的方法是不检查代码,除非您使用它检查测试。

我不是第一次写测试的忠实粉丝。但我强烈要求的一件事是必须在中使用测试检查代码。甚至不到一个小时左右, togther 。我认为只要它们一起出现,它们的编写顺序就不那么重要了。

答案 7 :(得分:4)

小而高度凝聚力的方法。我学的很难。想象一下,你有一个处理身份验证的公共方法。也许你做过TDD,但是如果这个方法很大,那就很难调试。相反,如果#authenticate方法以更加伪编码的方式执行操作,调用其他小方法(可能受到保护),当出现错误时,很容易为这些小方法编写新测试并找到错误方法。

答案 8 :(得分:4)

你在OOP中学到了第一件东西,但是很多人似乎忘记了:代码对接口,而不是实现

答案 9 :(得分:4)

我确信我会因此而被投票,但无论如何我都会发表意见:)

虽然这里的许多建议都很好,但我认为需要稍微调整一下。目标是编写可更改和可维护的更强大的软件。

目标不是让代码可以单元测试。尽管可测试代码不是目标,但仍然需要付出很多努力使代码更“可测试”。这听起来真的很好,我确信它给了人们温暖的模糊,但事实是所有这些技术,框架,测试等都需要付出代价。

它们在培训,维护,生产力开销等方面花费了大量时间。有时它值得,有时它不值得,但你不应该打开眼罩并提前充电,使你的代码更“可测试”。

答案 10 :(得分:4)

花一些时间重构不可测试的代码以使其可测试。编写测试并获得95%的覆盖率。这样做教会了我编写可测试代码所需要的全部知识。我并不反对TDD,但是学习使代码可测试或不可测试的具体细节可以帮助您在设计时考虑可测试性。

答案 11 :(得分:4)

答案 12 :(得分:3)

我尽可能使用测试驱动开发,因此我没有任何无法进行单元测试的代码。除非首先存在单元测试,否则它将不存在。

答案 13 :(得分:3)

1.Using a framework/pattern like MVC to separate your UI from you
business logic will help a lot. 
2. Use dependency injection so you can create mock test objects.
3. Use interfaces.

答案 14 :(得分:2)

查看此演讲Automated Testing Patterns and Smells。 对我而言,主要的收获之一是确保UnitTest代码具有高质量。如果代码记录良好且编写得很好,那么每个人都会有动力保持这一点。

答案 15 :(得分:1)

准备好您的代码是可测试的:

  • 记录您的假设和排除。
  • 避免使用不止一件事的大型复杂类 - 记住single responsibility principle
  • 如果可能,使用接口来分离交互并允许注入模拟对象。
  • 如果可能,请将pubic方法设为virtual,以允许模拟对象模拟它们。
  • 如果可能,在设计中使用组合而不是继承 - 这也鼓励(并支持)将行为封装到接口中。
  • 如果可能,请使用dependency injection库(或DI实践)为实例提供外部依赖项。

要充分利用单元测试,请考虑以下事项:

  • 教育您自己和您的开发团队了解您打算使用的单元测试框架,模拟库和测试工具的功能。当你真正开始编写测试时,了解他们能做什么和不能做什么都是必不可少的。
  • 在开始编写测试之前计划好测试。确定要包含在测试中的边缘情况,约束,前置条件,后置条件和排除。
  • 修复损坏的测试,尽可能地发现它们。测试可帮助您发现代码中的缺陷和潜在问题。如果您的测试被破坏,您就打开了以后必须修理更多东西的大门。
  • 如果您在团队中遵循代码审核流程,代码也会审核您的单元测试。单元测试与任何其他代码一样是系统的一部分 - 评论有助于识别测试中的弱点,就像系统代码一样。

答案 16 :(得分:1)

No Statics - 你无法模仿静态。

谷歌还有一个工具可以衡量代码的可测试性......

答案 17 :(得分:1)

我一直在努力寻找一个过程,在这个过程中,单元测试不是一件苦差事,而是我真正想做的事情。根据我的经验,一个非常重要的因素是你的工具。我做了很多ActionScript工作,遗憾的是,这些工具有些局限,例如没有IDE集成和缺乏更高级的模拟框架(但好的东西是即将到来的,所以这里没有抱怨!)。我之前已经通过更成熟的测试框架完成了测试驱动开发,它确实是一种更加愉悦的体验,但仍然感觉像是一些苦差事。

最近我开始以不同的方式编写代码。我曾经开始写测试,看着他们失败,编写代码使测试成功,冲洗和重复以及所有这些。

然而,现在,我开始编写接口,几乎无论我将要做什么。首先,我当然试图找出问题并考虑解决方案。然后我开始编写接口,以获得代码和通信的抽象感觉。那时,我通常意识到由于我没有完全理解这个问题,我根本没有找到问题的正确解决方案。所以我回去,修改解决方案并修改我的界面。当我觉得接口反映了我的解决方案时,我实际上从编写实现开始,而不是测试。当我有一些实施(草案实施,通常是婴儿步骤),我开始测试它。我一直在测试和实施之间回过头来,前进几步。由于我拥有一切接口,因此注入模拟非常容易。

我发现这样的工作,对其他实现知之甚少,只与界面交谈的类非常自由。它让我不再考虑另一个类的实现,我可以专注于当前的单元。我需要知道的是界面提供的合同。

但是,是的,我仍然在努力制定一个每次都非常出色地运作的过程。

哦,我还想补充一点,我不会为所有内容编写测试。除了获取/设置变量之外没有做太多的香草属性对于测试是无用的。他们通过语言合同获得工作。如果他们不这样做,我的问题会比我的单位不可测试更糟糕。

答案 18 :(得分:0)

您不一定需要“让您的代码更加友好地进行单元测试”。

相反,可以使用模拟工具包来消除可测试性问题。 其中一个工具包是JMockit

相关问题