How to unit test static methods?

At the 1st of march I attended Joy of coding conference (joyofcoding.org). It was one of the most interesting conferences I have been so far and quality of the content and percentage of information I find useful was very high.

One of the sessions there was “Testing and refactoring Legacy Code” from Sandro Mancuso. And he shown how you should deal with testing of static methods.

His main argument was that you should not test it. Instead, replace it with testable components and test against them. So frameworks like Powermock which allows you to test static methods, actually is a wrong way of doing it. And there is short example how you can do it more elegant (it is example from me, not the example actually shown by Sandro).

Lets say you have a service which calls repository to persist an entity:

public class Service {       
    public Entity createNewEntity() {
        return Repository.create(new Entity());
    }

    ... some more methods below .....
}

Unfortunately, the imaginary developer for whatever reason made Repository as an utility class containing only static methods. For example, something like following:

public class Repository {
    private static OrmTool orm = new OrmTool();

    public static Entity create(Entity entity) {
        return orm.insert(entity);
    }
    
    .....
}

So what is the problem with such approach? Well, in this case attempt to test Service#createNewEntity method will require entire integration with a Orm tool or/and underlying database. There are two most common solutions I have seen to solve it so far – use powerful framework to mock Repository.create method (powermock, for example). Another way is to configure your Orm to use some test (often inmemory, like, Hsqldb) database.

While both approaches are valid – the first one is very framework specific and the second one is more integration test then unit.

So how Sandro suggests to fix it?

Of course, we write test first!

Lets say we use mockito (my personal preference) as a mocking framework. Then the unit test could look like something following:

public class ServiceTest {
    private Repository repository = mock(Repository.class);
    private Service service = new Service(repository);

    @Test
    public void createsNewEntity() {
        service.createNewEntity();

        verify(repository).insert(eq(new Entity()));
    }
}

So from the test above it is quite clear that what our service should do it is just call to an insert method of a repository.

But wait a second, we do not have “insert” in the Repository utility. Right! That is exactly small and powerful trick Sandro illustrated.

In our situation we would convert utility class Repository to the usual class (component), inject it to the service and add one instance method wich will be just delegate to a static create method. Then our code would look like:

The service with injected repository:

public class Service {
    private Repository repository;

    public Service(Repository repository) {
        this.repository = repository;
    }

    public Entity createNewEntity() {
        return repository.insert(new Entity());
    }
}

Note that we use new method “insert” here. And repository will look like:

public class Repository {
    private static OrmTool orm = new OrmTool();

    public static Entity create(Entity entity) {
        return orm.insert(entity);
    }

    public Entity insert(Entity entity) {
        return Repository.create(entity);
    }

    .....
}

As next step you can do the same trick for the all other calls to the static method and replace them one by one. And when it is done you can just inline it and get rid of it. That’s it!

Pretty simple and obvious, but it is amazing how such simple trick can be overlooked by a lots of developers (including myself).

P.S. Enjoy it and refactor with pleasure!

Leave a comment

Leave a comment