Justin Edwards
Justin Edwards

Reputation: 171

Dependency Injection Does not work in Models or Tests in Play Framework 2.4.x

I am trying to write some unit tests for my Play Framework 2.4.6 application. I need WS for my purposes testing. However, when I used the documention's method to inject WS I end up with a null pointer if used in a test or a model. However, the injection works perfectly if I install it into one of my controllers.

Here is my test:

import org.junit.Test;
import play.test.WithServer;
import play.libs.ws.*;
import javax.inject.Inject;
import static play.test.Helpers.running;
import static play.test.Helpers.testServer;

public class UserProfileTests extends WithServer {
    @Inject
    WSClient ws;

    @Test
    public void demographicTest() {

        System.out.println(ws.toString()); //null pointer exception

        running(testServer(3333), () -> {
            System.out.println(ws.toString()); //null pointer exception
        });

    }
}

Here is the console output when running activator test

[error] Test UserProfileTests.demographicTest failed: java.lang.NullPointerException: null, took 5.291 sec
[error]     at UserProfileTests.demographicTest(UserProfileTests.java:15)
[error]     ...
[error] Failed: Total 4, Failed 1, Errors 0, Passed 3
[error] Failed tests:
[error]     UserProfileTests
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 9 s, completed Jan 21, 2016 11:54:49 AM

I'm sure I'm just fundamentally misunderstanding something about dependency injection or how the system works. Any help would be very appreciated.

Upvotes: 3

Views: 1556

Answers (1)

marcospereira
marcospereira

Reputation: 12214

Since tests should be extremely focused on just one particular scanario/object, I don't think you need to worry about how to do Dependency Injection for your tests and, instead, just instantiate what you need. Here is a way to instantiate using the application Injector:

import org.junit.Before;
import org.junit.Test;
import play.libs.ws.WSClient;
import play.test.WithServer;

public class UserProfileTests extends WithServer {

    private WSClient ws;

    @Before
    public void injectWs() {
        ws = app.injector().instanceOf(WSClient.class);
    }

    @Test
    public void demographicTest() {
        System.out.println(ws);
    }
}

But, of course, you could also just instantiate the ws by hand or mock it if you want.

About the models, their lifecycle is not handled by Guice and then, there is no direct way to do Dependency Injection at models. You can always find a way to do that, but should you? What will happen if try to load 100 objects from the database and then have to inject a dependency in each of these objects?

Besides the (likely) performance problem, maybe you are also violating Single Responsibility Principle here and your models are doing to much work.

Upvotes: 6

Related Questions