Is the Singleton design pattern incompatible
with unit testing? I think it is. Singleton assures us that our program will
have only one instance of a particular class and that there will be a global
access point for it. Put those two ideas together,
and what you have is a global variable that can't be replaced. Doesn't sound so bad? Well, try this out: write a set of unit tests which exercise clients of
that variable. If one test modifies
global state, and another uses it, you could have one hell of a debugging chore
when your tests fail. I won’t elaborate
on the pain here. If you’ve ever encountered
it, you know about it.
The Singleton pattern allows only one instance of each singleton class in a system. In Java, that’s one per classloader or JVM, and in C++ it's one per executable. That's fine when you have just one system, but each test is a little "system" too; and if each of the tests needs to use a particular singleton, they can't be complete or independent because the singleton, through it's creation characteristics, has defined the scope of the "system": it's the JVM, the .NET runtime, or the interpreter. When you think about it, isn’t it a little arrogant for a class to decide that?
One of the easiest ways to get past the impasse is to break the singleton property, the requirement that there can be only one created instance. If you can provide some way to set a singleton’s instance, you’re on the path to create a fakable singleton, or fingleton. You can use a configuration file to dynamically load a fake for testing, or write a static setter to set the instance. In some languages, you can use reflective tricks, or even conditionally compile the setter method so that it is only available when you are testing, but in the end, you are able to create more than one instance of that class: what you have is a fingleton, not a singleton.
I think that many of us have known that Singleton is broken for years, but we just haven't stated it out loud. There are always the little exceptions. For instance, singletons cause no trouble at all if we can’t affect state through them, but cases like that don’t come up often. If you have an immutable data structure, it's overkill to make it a singleton. Likewise, if you have something stateless like a factory, well yes, it’s great to have one distinguished instance, but what do you do if you need to mock it? There’s that singleton property, getting in the way again.
Faced with singleton's troubles, many people turn their singletons into fingletons and attempt to protect their instances as best they can. There are many protection mechanisms, but it seems that as they become more elaborate, the object becomes harder to use in a testing situation. Sometimes the simplest answer is the best answer: supply a static method on your singleton called setTestingInstance.. unprotect your constructor and introduce an interface. Create mocks for your "singleton".. eventually you may be able to pass it around by reference rather than using it globally.
Yes, there are cases where you might want more protection than this and in those cases you should add whatever protection you feel you need, but let’s face it, on most projects if your teammates can't refrain from calling a static method named setTestingInstance in production code, your project is probably in trouble no matter what you do. On the other hand, if they can, it's easier to keep your software testable, correct and maintainable.