【问题标题】:Why is it hard to unit test a system that depends on singletons?为什么很难对依赖单例的系统进行单元测试?
【发布时间】:2010-10-06 21:13:34
【问题描述】:

我已经阅读了支持和反对使用单例模式的案例。一个常见的反对案例描述了单例单元测试的困难,但我不清楚这是为什么?如果单元测试是构建的一部分,您不能只引用单例并在需要时使用它吗? (我是从 java 的角度考虑的,但我想这不重要)

【问题讨论】:

    标签: unit-testing singleton


    【解决方案1】:

    TL;DR 在所有测试之间共享同一个对象,这可能会很痛苦。

    如果单例具有某种状态,并且您在其上运行多个测试,那么测试的顺序可能会成为一个问题。想象一个单例“MailStore”,它包含一个消息列表。我想编写一个用于列出邮件的单元测试,以及另一个用于删除它们的单元测试。

    当然,如果“列表”在“删除”之前运行,也许没问题。如果“delete”在“list”之前运行,那么我们会很挣扎,因为没有什么可删除的。 (结果会根据运行测试的顺序而变化。)

    【讨论】:

      【解决方案2】:

      关于这方面的一篇很棒的文章是Singletons are Pathological Liars。这通过一个简单的示例描述了为什么使用单例进行测试会出乎意料地困难。

      【讨论】:

      • 好文章,+1。我希望文章更改的唯一内容是最后的示例......对我来说,charge() 方法在 CreditCardProcessor 上并将卡和金额作为参数更有意义:)
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        单例是一个问题有几个原因:

        • 它们是服务定位器的一个特例,它提供了一种机制来“获取其中一个”,在需要时不一定容易覆盖。
        • 它们提供了读取或写入全局变量的入口点。将这些全局变量包装在一个对象中,该对象只有一个可通过单例模式全局访问的实例,并不会神奇地使它们不再是全局变量。
        • 它们也很麻烦维护。例如,当他们不再是真正的 Singleton 时会发生什么——也许您必须访问两个数据库而不是“数据库”?

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            This Google Techtalk 在单元测试中很好地描述了单例和全局状态的问题。

            【讨论】:

              【解决方案7】:

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

              但是,如果您想创建和测试一个不同的,可能使用不同的构造函数/工厂方法参数怎么办?你重新启动JVM吗?或者创建您的单身人士,使其不是真正单身人士并且可以重置?不好。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-10-04
                • 2016-11-13
                • 1970-01-01
                • 2014-05-29
                • 1970-01-01
                • 1970-01-01
                • 2014-03-15
                相关资源
                最近更新 更多