Can’t test that Singleton? Try Dependency Injection!

So you want to test this method:

public class Client {

    public int process(Params params) {
        final Server server = Server.getInstance();
        final Data data = server.retrieveDate(params);
        // do stuff
    }
}

We don’t want to retrieve an instance of a real server for our little unit-test, so how can we test this method?

It is hard to test code that uses singletons.

We don’t control the creation of the singleton object, as it is performed inside a static method. There is no way to mock the object in order to test the behavior of our method in isolation.

Refactor it to use Dependency Injection.

You can refactor Client to avoid using the singleton pattern. Instead of obtaining the Server instance from the static getInstance() method, allow Client to accept it through its constructor.

public class Client {
    private final Server server;  

    public Client(Server server) {
        this.server = server;
    }  

    public int process(Params params) {
        final Data data = server.retrieveData(params);
        // do stuff
    }
}

Let’s write that test now:

@Test
public void testConnectionUpTime() {
    final Server mockServer = Mockito.mock(Server.class);
    final Params params = // ...
    Mockito.when(mockServer.process(params)).thenReturn(5);
    final Client client = new Client(mockServer);
    assertEquals(5, client.process(params));
}

The code is now both clearer and testable.

The dependency between the client and the server is now explicit: Client client = new Client(server);. There is no way a developer creates a client instance without noticing that a server instance must be configured: it is a parameter in the constructor.

The singleton allowed to create a client instance without configuring the server in advance. The object would be successfully created and the application would execute, until one of the methods runs into a non-configured/non-reachable/null server and fail at runtime :’-(

  • Share/Bookmark

Related posts

You can leave a response, or trackback from your own site.

3 Responses to “Can’t test that Singleton? Try Dependency Injection!”

  1. Your point is valueble for me. Thanks. Could you please suggest the suitable 5 mile walkie talkie info!…

  2. david says:

    Dependency injection to mock singleton ?
    A Very bypassing solution.
    If the singleton is central and you need the singleton in 20 classes of your application, you will add the dependency in the 20 classes ?
    You can but you make your design heavier.

  3. But most likely those 20 classes only need access to specific objects/services that the server provides. So you would inject only what they really need (following the Law of Demeter). This way, they are not even aware of the server class, which might come in handy in a future refactoring.

    Still, sometimes there are trade-offs to make. What can easily happen with dependency injection is that your constructors end up having too many arguments. Another problem is that some classes are just forwarding objects that they don’t even need to others.

    To alleviate this, you can “start the dependency injection later”: let a selected group of central classes get the server instance, and inject from there.

    Not sure I made my point. It’s sort of difficult to explain without an example and with my limited literary skills :)

Leave a Reply