Search code examples
javaunit-testingplayframeworkmockingintegration-testing

Testing Controllers In Play Framework


I am using Play Framework and using Java as the language of choice. I have a Controller which makes a REST call to an external service. I intend to mock the external service, so that I can test the functionality of my controller. To achieve this, I have created my test cases as shown below (sample). I am embedding a server within my test to mock the external service.

public class SomeControllerTest extends WithApplication {

private static Server SERVER;

@Override
protected Application provideApplication() {
    final Module testModule = new AbstractModule() {
        @Override
        public void configure() {
            bind(AppDao.class).to(MockAppDaoImpl.class);
        }
    };
    return new GuiceApplicationBuilder().in(Environment.simple()).overrides(testModule).build();
}

@BeforeClass
public static void setup() {
    Router router = new RoutingDsl()
            .POST("/api/users")
            .routeTo(() -> created())
            .build();
    SERVER = Server.forRouter(router, 33373);
    PORT = SERVER.httpPort();
}

@AfterClass
public static void tearDown() {
    SERVER.stop();
}

@Test
public void testCreateUser() {
    ObjectNode obj = Json.newObject();
    obj.put("name", "John Doe");
    obj.put("email", "[email protected]");
    Http.RequestBuilder request = new Http.RequestBuilder()
            .method(POST)
            .bodyJson(obj)
            .uri("/some/url/here");
    Result result = route(request);
    assertEquals(ERR_MSG_STATUS_CODE, CREATED, result.status());
    assertEquals(ERR_MSG_CONTENT_TYPE, Http.MimeTypes.JSON, result.contentType().get());
}

My expectation is that when I run the test, the mock server would run and based on my application's test configuration, my controller will make a call to the mock server which would return 201 and my test case would pass. But, this doesn't happen, because as soon as setup() method completes, the mock server is killed, and my controller cannot make a call to it.

What am I doing wrong here?


Solution

  • Testing of controller should be rather done by inheritance from WithApplication

    public class TestController extends WithApplication {
       @Test  
       public void testSomething() {  
           Helpers.running(Helpers.fakeApplication(), () -> {  
               // put test stuff  
               // put asserts  
           });
       }  
    }
    

    In order to test a controller method use Helpers.fakeRequest and reverse routing. The external service may be just mocked with mockito or other mocking framework you like.

    You can find here several examples.