Unit testing code that calls static methods

I have read most of the questions related to us ( here , here and there ). The final question suggests four alternatives for creating code that invokes static methods to be tested. I want to ask about my specific case: we have a “business logic” or “rule” project that contains 45 static classes (no state, only static methods). Moreover, they are not easily verified on their own: most of them refer to the database and file system. It's not so bad anyway: they use a unique instance of some Mapper class to access the database (all Mappers are Singletons). Whenever I try to unit test something, I run into this wall. The biggest problem is that this is a very, very important code, and changes to it must be carefully planned. My question is: how can I make this block more reliable? Should I write 45 interfaces and use dependency injection? However, how can I drown / mock mappers?

PS: I read Michael Feathers "Working with Legacy Code", so direct links are welcome (other books too :)

Change Since some people have stated that solutions may be platform dependent, I am working on .NET (C # and some VB.NET)

+7
source share
5 answers

The current situation is likely to be that no one dares to change anything in the code, because it may break unexpectedly. Make sure everyone understands that you are improving the situation: your changes may break the code, but unlike the previous ones, these breakdowns will be found, and as soon as they are found, they will be fixed forever.

However, the next step depends on your experience and your credit with the team. If you want to play it safe, use this code (Java syntax):

Mapper { public static Mapper INSTANCE = new Mapper(); // NEW code protected void doImpl() { // NEW CODE ... code copied from impl()... // OLD code, NEW PLACE } public static void impl() { // OLD code INSTANCE.doImpl(); // NEW code } // OLD code ... } 

This is a very simple change that allows you to overwrite INSTANCE from your tests. You do nothing for production code, and by default the code will behave exactly the same as before.

This way you can replace one method at a time. You can stop following this path at any time - each change takes only a couple of minutes, and this is refactoring: the code does exactly what it did before. Since each change is so small and can not break anything, you can replace one method, write all unit tests that you could not write before, rinse, repeat. Finally, if you do not want / do not have to process all static methods, this approach gives you all the freedom of action you could ask for.

In the second step, you can introduce DI or any other technology that will make you happy. The advantage of this approach: when you come to complex changes, you will already have unit tests that protect you.

If you started with DI, you would have to change a lot of code in all places - without proper unit tests that could protect you.

+10
source

Make the Mapper class interface and replace the mapper functionality with the new moc implementation. I think you will need to implement an abstract factory that will generate instances of Mappers. So make IMapperFactory, and two implementations of this DBMapperFactory and MocMapperFactory pass an instance of this object to your code, where you access the Mappers and generate them using that instance.

Gl.

+3
source

Your question is really platform related, in the Microsoft world you can use Microsoft Moles to test static methods. And the layout of static methods.

There are probably other tools in the java world, or you should avoid using statics.

Other platforms have other tools, etc.

In general, any static method will make your code less verifiable. In my version, it is better to avoid statics and singlets (global state) at all costs. Test code is the most important part of your code if you change something later. Checked code is also usually readable.

Moles and Pex

+2
source

A static class can be mocked, although without knowing which language / environment you are using, there is no way to tell how to do it.

I had a code base that turned out to be exactly what you said; we created default interfaces and implementations from several tens of static classes (we do not generate panic coding). By default, impls are simply delegated to singletones.

Callers were switched to DI using default implants, but then it was much easier to test. Static classes with dependencies on other static classes or single movements have switched to using implants by default.

You mock a singleon just like any other class - if it has getInstance (or the equivalent), you can make it return whatever you want. Or you can go on the same route and use DI.

+1
source

Great question! You can make fun of your Mapper class by creating a new one that inherits from the singleton Mapper class, and then use it to intercept all calls to your database.

+1
source

All Articles