为什么难以对依赖于单身的系统进行单元测试?

时间:2010-10-06 21:13:35

标签: unit-testing singleton

我已经阅读过使用单例模式的案例。一个常见的案例描述了单身人士单元测试中的困难,但我不清楚为什么会这样呢?如果单元测试是构建的一部分,你不能只引用单例并在需要时使用它吗? (我从java的角度思考,但我想这不重要)

7 个答案:

答案 0 :(得分:18)

关于这一点的好文章是Singletons are Pathological Liars。这使用一个简单的例子描述了为什么使用单例测试出乎意料的困难。

答案 1 :(得分:5)

如果您引用存在于被测试类之外的单例类,则您不再具有真正的单元测试。您现在正在测试两个单元 - 目标类单例,而不是测试单个单元 - 目标类。

还有一个事实是单身对象倾向于有状态。为了使单元测试可重复,当单元测试完成时,需要回滚那些状态更改。或者,您必须创建在运行每个测试后销毁的单例的模拟版本。在源代码和运行时间中都会增加相当大的开销。

答案 2 :(得分:4)

因为单例是一个OOPish全局变量。基本上,依赖于使用单例(直接或间接)的所有函数都不能保证是确定性的(即,您不能指望函数为相同的输入返回相同的输出T 每次运行)。

答案 3 :(得分:4)

TL; DR所有测试之间共享相同的对象,这可能会变得很痛苦。

如果单例持有某种状态,并且你对它运行多次测试,那么测试的顺序可能会成为一个问题。想象一下单身" MailStore",它包含一个消息列表。我想为列出邮件编写一个单元测试,另一个用于删除它们。

当然如果"列表"在"删除"之前运行,也许这没关系。如果"删除"在" list"之前运行,然后我们努力,因为没有什么可以删除。 (结果会根据运行测试的顺序而改变。)

答案 4 :(得分:3)

单身人士是一个问题有几个原因:

  • 它们是服务定位器的一个特例,它提供了一种机制来“让我找到其中一个”,在需要时不一定容易被覆盖。
  • 它们提供了读取或写入全局变量的入口点。将这些全局变量包含在一个只有一个可通过Singleton模式全局访问的实例的对象中,并不会让它们成为全局变量。
  • 他们也很难维修。例如,当他们不再是一个真正的单身人士时会发生什么 - 也许你必须访问两个数据库而不是“数据库”?

答案 5 :(得分:2)

在单元测试方面,

This Google Techtalk可以很好地描述单例和全局状态的问题。

答案 6 :(得分:-2)

我不记得曾经读过这个,但我怀疑问题在于你只能创建一个。在某些情况下,这可能不是问题,只需正常测试即可。

但是如果你想创建和测试另一个,可能有不同的构造函数/工厂方法参数呢?你重启JVM了吗?或者创建你的单身人士,以便它不是真的单身并且可以重置?不好。