Unit Testing Singletons

Moved from SingletonPattern

I don't know why UnitTests and Singletons are incompatible or problematic. When we write our unit tests, if we need a particular singleton for that test, we just create an instance of an appropriate subclass on the stack and when that particular test is finished the singleton instance is automatically destructed. We often create a special subclass of the singleton specially for the particular test we are writing. This seems to work pretty well. -- JamesCrawford

The basic problem we had with Singletons and UnitTests was that the tests needed to ensure that the Singletons used were test versions and creation tends to be encapsulated within the singleton class itself. We ended up going back to GlobalVariables which were created by the UnitTests within their setup() methods.

Global variables are lazy, but they don't worry me in small to medium sized applications if there are small numbers of them.

As a corollary, I noticed that with UnitTests you need to make all your constructors work through factories, again so that you can over-ride them to produce test versions of your particular classes. -- RichardDevelyn

One simple way to make any Singleton fit for Unit Testing is by allowing your unit-testing code to inject the singleton instance into the singleton. Nothing in the pattern forbids you to implement an "injectInstance" method on it. -- PeterKaptein

Just recently, I've been attempting to get my head around a body of code that I've not seen before.

The system is written in C++, though I don't think that this has anything in particular to do with my problem.

As part of this process, I'm attempting to retrofit UnitTests for the pieces of functionality that I have to add/alter.

As I implement each unit test, I find that I have to drag in a lot of extra code to make it all compile and run. While the amount of coupling is slightly disturbing, it's not a major problem.

What I am finding to be the problem is that the code makes extensive use of singletons, for example.

 // widget.h
 class Widget {
  static Widget *m_instance;
 public:
  static getInstance() { return m_instance; }
 };

inline Widget *getWidget() { return Widget::getInstance(); }

Thus, any object in the system can get at the singleton Widget. This, I'm finding, greatly increases the InvisibleCoupling? of the system. This makes it harder to test, because:

Thus, SingletonsAreEvil?

My job has similar singleton code, but with one difference - getInstance checks the value of the static pointer, and if it's 0, creates the instance, thus avoiding the first point above; as for the need to create the instance before some point in the code (or after some point), that's not unique to singletons - anything whose creation depends of state can have that - starting a database transaction depends on a database connection being established, opening a database must be done after the database name is read from the config file, etc. -- PeteHardie

'If you have three singletons you want to convert to regular objects, you do not have to create them all in the same place. If you have only one singleton that you want to replace, it does get created someplace, but so does everything. -- MichaelFeathers'

Centralized creation is very different than creation on use. With on use new modules can easily and transparently enter the system.

Plus, I'd advocate a singleton be a front for another object rather than have the object present its own singleton interface. This way the object be used on its own, say during testing, without worrying about its singleton nature. That pretty much defeats the purpose of a singleton you know. If you can create instances of it separately, then it's not a singleton.

-- TheFool?

In my previous project I'd found that usage (and testing) of singletons in big projects is quite important. To enable unit-testing with singletons, we were creating singletons with additional auxiliary method, which released current instance (if any). Thus, in TestCase SetUp? we could release the already-created singleton instance, instantiate the needed subclass of the singleton (which was usually a mock) and in TearDown? release the instance of the singleton.

-- IvanTarasov

Right, MockObjects are a good way to deal with areas of appropriate coupling. However, too much coupling and too much SetUp? and TearDown? is a major DesignSmell (see CodeSmell and ExpensiveSetUpSmell). Also, it seems that some of the code may have been writing before the UnitTests from the wording above. In that case, the difficulty in writing the UnitTests is an indication (smell) that the interface might want to be modified (improved) to make it easier to test. Ideally, the UnitTestIsTheMock. To, me that's a good general approach to DoSimpleThings in TestDrivenDevelopment. Cheers, -- JasonNocks


That pretty much defeats the purpose of a singleton you know. If you can create instances of it separately, it's not a singleton.

As long as the contract with the user is preserved, the singletonness is preserved. The fact that you can tear down and setup for unit tests doesn't change that.


CategoryTesting

EditText of this page (last edited June 1, 2012) or FindPage with title or text search