单身人士测试和子类化

时间:2011-08-04 13:41:20

标签: design-patterns testing singleton subclassing

我在使用picocontainer时看到了这一点。他们说你必须避免单身。 因为Singleton模式使得类(以及可能依赖于它的所有其他类)几乎不可能是可测试的。子类化或为Singleton类创建模拟对象非常困难。

但是如果你绝对需要它,那么测试和子类化问题是否有解决方法?

3 个答案:

答案 0 :(得分:5)

难以测试单例的是执行单例的代码(意味着public static MySingleton getInstance() {...}样板)。使用像Picocontainer或Guice或Spring这样的控件反转容器可以从对象中删除这个问题,所以现在:

  • 它可以被实例化,并且可以在测试中将协作者插入其中而不会出现问题。

  • 调用单例的代码不必知道它正在查找哪个类(如果必须调用静态方法,则需要知道它。)

我将picocontainer网站上的建议解释为与此类似。他们告诉您的是,让我们的容器为您管理组件的范围,不要将范围执行代码硬连接到它们中。

答案 1 :(得分:1)

如果你必须有单身人士:

  1. 有一个描述每个单身人士的界面
  2. 从全球/单身ServiceLocator
  3. 访问您的单身人士
  4. 在测试期间切换在ServiceLocator中注册的实例
  5. 示例:

    interface IBankApi
    {
       public void MakeDeposity(int accountNumber, int dollarAmount);
       // ...
    }
    
    public class RealBankApi : IBankApi { ... }
    
    // startup code
    serviceLocator.Register<IBankApi>(new RealBankApi());
    
    // code using the API
    serviceLocator.Resolve<IBankApi>().MakeDeposit(...);
    
    // test code setup
    class FakeBankApi : IBankApi { ... }
    serviceLocator.Register<IBankApi>(new FakeBankApi());
    

答案 2 :(得分:1)

使用IOC(控制反转)而不是在第一次使用时启动的单例也有其他原因。

Singleton-initialisation可能会遭遇(着名的)多线程问题,其中两个线程同时第一次尝试访问它。后续访问很可能是正确同步的,但第一个很难做到。

我发现使用IOC的另一个巨大优势是初始化时可能发生错误。你不希望这种情况发生在“第一次使用”,你想在早期就知道这个失败,当然这样更容易处理错误。

最后,关于测试,IOC提供了完美的模型来隔离组件,根据需要替换它们,并以更灵活的方式将不同的组合结合在一起,从而为单元测试和集成测试提供完美的线束,作为一个很好的回滚机制,根本不需要恢复任何代码。

单身经常被使用的一般原因不是为了一个人而是为了全球性。如果您的项目得到了正确管理,那么您将拥有一个全局对象,所有其他对象都会“注册”(因此您的IOC模型会将其挂起),并且在全局可用的同时仍可配置。