Singleton and unit testing

前端 未结 12 1541
一生所求
一生所求 2021-01-30 10:24

The Effective Java has the following statement on unit testing singletons

Making a class a singleton can make it difficult to test its clients, as it’s im

12条回答
  •  春和景丽
    2021-01-30 11:22

    The problem isn't testing singletons themselves; the book is saying that if a class you are trying to test depends on a singleton, then you will likely have problems.

    Unless, that is, you (1) make the singleton implement an interface, and (2) inject the singleton to your class using that interface.

    For example, singletons are typically instantiated directly like this:

    public class MyClass
    {
        private MySingleton __s = MySingleton.getInstance() ;
    
        ...
    }
    

    MyClass may now be very difficult to automatedly test. For example, as @Boris Pavlović notes in his answer, if the singleton's behaviour is based on the system time, your tests are now also dependent on the system time, and you may not be able to test cases that, say, depend on the day of the week.

    However, if your singleton "implements an interface that serves as its type" then you can still use a singleton implementation of that interface, so long as you pass it in:

    public class SomeSingleton
        implements SomeInterface
    {
        ...
    }
    
    public class MyClass
    {
        private SomeInterface __s ;
    
        public MyClass( SomeInterface s )
        {
            __s = s ;
        }
    
        ...
    }
    
    ...
    
    MyClass m = new MyClass( SomeSingleton.getInstance() ) ;
    

    From the perspective of testing MyClass you now don't care if SomeSingleton is singleton or not: you can also pass in any other implementation you want, including the singleton implementation, but most likely you'll use a mock of some sort which you control from your tests.

    BTW, this is NOT the way to do it:

    public class MyClass
    {
        private SomeInterface __s = SomeSingleton.getInstance() ;
    
        public MyClass()
        {
        }
    
        ...
    }
    

    That still works out the same at run-time, but for testing you are now again dependent on SomeSingleton.

提交回复
热议问题