【发布时间】:2010-10-06 21:13:34
【问题描述】:
我已经阅读了支持和反对使用单例模式的案例。一个常见的反对案例描述了单例单元测试的困难,但我不清楚这是为什么?如果单元测试是构建的一部分,您不能只引用单例并在需要时使用它吗? (我是从 java 的角度考虑的,但我想这不重要)
【问题讨论】:
我已经阅读了支持和反对使用单例模式的案例。一个常见的反对案例描述了单例单元测试的困难,但我不清楚这是为什么?如果单元测试是构建的一部分,您不能只引用单例并在需要时使用它吗? (我是从 java 的角度考虑的,但我想这不重要)
【问题讨论】:
TL;DR 在所有测试之间共享同一个对象,这可能会很痛苦。
如果单例具有某种状态,并且您在其上运行多个测试,那么测试的顺序可能会成为一个问题。想象一个单例“MailStore”,它包含一个消息列表。我想编写一个用于列出邮件的单元测试,以及另一个用于删除它们的单元测试。
当然,如果“列表”在“删除”之前运行,也许没问题。如果“delete”在“list”之前运行,那么我们会很挣扎,因为没有什么可删除的。 (结果会根据运行测试的顺序而变化。)
【讨论】:
关于这方面的一篇很棒的文章是Singletons are Pathological Liars。这通过一个简单的示例描述了为什么使用单例进行测试会出乎意料地困难。
【讨论】:
如果你引用了一个存在于被测类之外的单例类,那么你就不再有真正的单元测试了。您现在测试的是两个单元,而不是测试单个单元 - 目标类 - 目标类和单例。
还有一个事实是单例对象往往具有状态。为了使单元测试可重复,这些状态更改需要在单元测试完成时回滚。或者,您必须创建一个模拟版本的单例,在每次测试运行后销毁。两者都在源代码和运行时间上增加了相当多的开销。
【讨论】:
单例是一个问题有几个原因:
【讨论】:
因为单例是一个 OOPish 全局变量。基本上,依赖于使用单例(直接或间接)的所有函数都不能保证是确定性的(即,您不能期望函数为相同的输入返回相同的输出 T each and every run )。
【讨论】:
This Google Techtalk 在单元测试中很好地描述了单例和全局状态的问题。
【讨论】:
我不记得读过那篇文章,但我怀疑问题在于您只能创建 一个。在某些情况下,这可能不是问题,只需正常测试即可。
但是,如果您想创建和测试一个不同的,可能使用不同的构造函数/工厂方法参数怎么办?你重新启动JVM吗?或者创建您的单身人士,使其不是真正单身人士并且可以重置?不好。
【讨论】: