Singletons and testing

| 15 Comments | 4 TrackBacks
When you need to jump through hoops to write tests you've done it wrong. Jonathan de Halleux writes about testing singletons and how he can subvert the standard C# singleton pattern to create a new singleton for each test he needs to run for the singleton. Omer then subverts the rules another way. Both are wrong.

Firstly Singletons are evil. Really. It's a useful pattern but it's way over used as some covert global variable. There really aren't that many cases where you really need a singleton and in all of those cases you NEVER need to allow the world to access your singleton via a static 'give me the instance' method that's called from everywhere. If you think you do then you need to work on your design some more, it's broken, you're wrong, you can just pass the object in to whoever needs it.

If you DO use the 'classic' singleton pattern and allow all and sundry to reach out and grab hold of your singleton object then you've just created a global variable and you've just coupled all of the code that uses it to a single implementation. This is bad news, both from a testing point of view and a code structure point of view. You're hiding the complexity, and, as you know, I don't like hidden complexity, I like it all to be explicit.

Half of the classic singleton is a useful concept; a class that has only one instance. The other half is bollocks; providing a global way to access that single instance.

The problem with both of these 'ways to cheat' when testing singletons is that they're solving the wrong problem. The problem that needs to be solved is testing the class that can only have one instance. Unfortunately the designers of that class were short-sighted and decided that there could only ever be one instance... Since the 'cheats' work, this is obviously not true. If the tests pass then it must be legit and safe to create and destroy multiple instances of the class. This means the singleton nature is secondary to the real work of the class in question. In this situation the class itself could be split in two. The class that does all the work and the singleton aspect that prevents multiple instances. If you do this then you can test the class and all aspects of the class without worrying about the singleton stuff. The singleton stuff would likely be a template; ok they're in C# so they don't have that amount of power in their tool, but the singleton part could still be separate... Orthogonal services; write the real code without worrying about the singleton state...

In the very, very, really very very, rare situations where you might need to access some global thing from everywhere in your program, and I'm thinking logging here, and I still don't buy it... The singleton in question should, IMHO, be a pluggable factory, and that fits fine with what I've said above. Write the object that you need to use as a singleton, test it and then supply it to a class that provides the singleton nature you require. If you do that then you can a) test the singleton class without 'clever' tricks and b) test classes that use the singleton with a mock that allows you to replace the functionality with something appropriate for testing.

Singletons, just say no.

4 TrackBacks

TITLE: More on singletons and testing URL: http://blogs.openogle.net/codesamurai/archive/2004/08/21/175.aspx IP: 80.163.113.238 BLOG NAME: C#deSamurai DATE: 08/21/2004 03:19:36 AM Read More

TITLE: Singleton Unit Testing (2): Follow up URL: http://blog.dotnetwiki.org/archive/2004/08/22/804.aspx IP: 209.132.240.214 BLOG NAME: Peli's Blog DATE: 08/22/2004 12:58:45 PM Read More

TITLE: Singleton Unit Testing (2): Follow up URL: http://dasblog.dotnetwiki.org/PermaLink,guid,777358ea-a106-421b-b0f5-607ed06c0c98.aspx IP: 209.132.240.214 BLOG NAME: Peli's Farm DATE: 06/06/2005 11:33:01 AM Read More

TITLE: Singleton Unit Testing (2): Follow up URL: http://dasblog.dotnetwiki.org/PermaLink,guid,777358ea-a106-421b-b0f5-607ed06c0c98.aspx IP: 209.132.240.214 BLOG NAME: Peli's Farm DATE: 06/06/2005 11:33:03 AM Read More

15 Comments

Another thing to hate about singletons is they by definition require adding dependencies, and increase coupling.

I've been meaning to write an article on this one, as I briefly mentioned a bug I found in refactoring my code. What I failed to mention was the refactor removed a singleton, and that was the source of the bug.

The problem was with the a singleton called "config." Config reads the configuration file and makes the setting available the the application. It seems to make sense that everything would want to see the config, but you consider dependencies.

For example, my proxy layer needed to get the address of the upstream server. In my first revision, I naively called the config singleton. The problem is that the proxy layer is then tightly coupled with this specific application. The config has all kinds of http settings which the proxy layer should know nothing about.

If I wanted to write a SMTP layer on top of the proxy layer the problem would become even more obvious.

The coupling and dependency issues are one of those things that becomes glaringly obvious if you're using TDD. It takes some time to get used to the slightly 'busier' constructor calls when you remove all the hidden dependencies and make it all explicit by using parameterize from above; but, IMHO it's worth getting used to.

I agree with you:

1)Singleton are evil,
2)In this situation the class itself could be split in two
-> it's refactoring time for me :)

Note that there must some situation where you are not the developper and they just gave you a singleton to test (you are the victim). In those case, I don't see how you can test it without "cheating"...

Very insightful post :)

Jonathan

In that situation I'd be tempted to turn around and throw the code back at the developer as untestable ;) I guess it depends on who has the most power...

I agree that the cheats might be useful and might be the only way to test a piece of code but, like many 'clever' tricks, I think the cleverness required should warn you that the design needs more work.

Pattern alert! Parametrize from above is typically the way to not require a singleton, in other words declare your 'singleton' class instance in your main and then pass it down to anything that requires it. Usually it is discipline that requires you pass the thing down an ever increasing chain of classes and lots of constructors that require your 'singleton' that put people off. The coupling isn't quite as nasty as a singleton but it is still there.

Barry

Agree that the coupling is there but it's visible and explicit (and I prefer that). Also, ideally, it's now coupling to an interface rather than a concrete class; you can replace the implementation. An alternative is a singleton implemented as a pluggable factory so that you don't need to pass the thing everywhere but you're still only coupled to an interface...

In my opinion the solution to the coupling problem is to use the Inversion of Control (IOC) idiom or Strategy Pattern.

If a module requires external data from its clients it can request that data via a strategy. In that case there is 0 coupling between the application singleton and the low level module.

Chris

Agree. IOC is, pretty much, what I've been referring to as paramaterize from above.

http://martinfowler.com/articles/injection.html

Hi Len,

I have posted a follow up of my blog entry, yours and omer technique at http://blog.dotnetwiki.org/archive/2004/08/22/804.aspx

Jonathan

Nice wrap up :)

Len,

I'm just wondering what your thoughts are on using Singleton as the pattern to represent hardware devices in software.

I'm working on a project right now, where I have used Singleton twice. Both times are for the two custom pieces of hardware I am using to get the job done. One is sitting on an ISA bus, and the other is sitting on a COM port.

I felt that Singleton was the right way to go about it, because there definitely should NOT be more than one instance of either, and the interactions with them need to be monitored, controlled, and Singleton gives me the perfect solution.

How would you handle the problem of custom hardware devices? Just instance classes where anyone can read/write into their instances, and who knows what the hell is going to come out the other side..

Or something like multiple instances, but all going through private static state data? (Which IMO sounds even worse)

As it stands, custom hardware can't be unit tested anyways. You can't write a test fixture which automatically inserts a bus drivers card into the card reader, while the test runs, and then has ot removed. I haven't worked out a way to wire up my autonomous robot arm into nunit attributes yet... ;)

Sean

I'd use a singleton. I'd probably keep the real work separate from the singleton aspects - so there would likely be a 'device controller' class and then a 'singleton device controller' class. I'd then likely have the device controller implement an interface; IDevice, and have things that use the controller be passed an instance of it. So, somewhere up near main you have the one and only call to the singleton’s GetInstance() method to return the one and only instance of the device...

The advantages of this are:
a) You can test what you can of the device controller class without worrying about the singleton aspects (though I take your point about testing hardware devices).
b) You can test every other part of the system without using real devices (if you want to).
c) You can only have one instance of the class as you're using a singleton.
d) The bulk of your code is coupled not to the device controller itself but to the IDevice interface...

Len,

Great. Close to how I've designed it anyway. With the exception of the calls to GetDevice(). They're still peppered through the code which I was planning to fix anyway. Interfsaces are all there, and all the code is referring to interfaces anyway, so nice and easy to refactor.

Sean

Removing the 'GetDevice()' calls will make the code easier to test. Alternatively, if you really feel you have to have the device accessible from all parts of the code rather than simply passing it in, you could make the GetDevice() "access point" a pluggable factory. Since you're already working via interfaces this should be easy. GetDevice() just returns an instance of IDevice and you set the instance in the factory from main() or whatever. Essentially you've separated the useful aspect of a singleton - one instance - from the painful aspect - access from everywhere. The pluggable factory singleton will then allow you to test the coupled code by plugging in a mock device...

Personally I prefer to explicitly pass the object in question in, rather than have code reach out to grab the object from a 'known place' but...

You prefer the "Tell, don't ask" style of coding. Same as me :)

Regards,

Sean

Leave a comment

About this Entry

Excellent piece on exceptions was the previous entry in this blog.

Brute force marshal by value is the next entry in this blog.

I usually write about C++ development on Windows platforms, but I often ramble on about other less technical stuff...

Find recent content on the main index or look in the archives to find all content.

I have other blogs...

Subscribe to feed The Server Framework - high performance server development
Subscribe to feed Lock Explorer - deadlock detection and multi-threaded performance tools
Subscribe to feed l'Hexapod - embedded electronics and robotics
Subscribe to feed MegèveSki - skiing