The intention of the Play server is to act as an intermediate service to another system, where the end-users access a small portion of functionality in a web browser on their smartphone.
The service functions as supposed to when connected to the real system. But, I want to have unit tests in a blackbox fashion. Testing the functionality from start to end. To avoid relying on the real system, where values change every day, I wanted to use the same approach as described in Testing web service clients and combine it with the route testing as shown in the example test from the play-java-seed, shown here for convenience:
public class HomeControllerTest extends WithApplication {
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
@Test
public void testIndex() {
Http.RequestBuilder request = new Http.RequestBuilder()
.method(GET)
.uri("/");
Result result = route(app, request);
assertEquals(OK, result.status());
}
}
My test code then looks as follows:
package controllers;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
import play.Application;
import play.inject.guice.GuiceApplicationBuilder;
import play.mvc.Result;
import play.mvc.Http.RequestBuilder;
import play.routing.*;
import play.server.Server;
import play.test.WithApplication;
import static play.mvc.Http.Status.*;
import static play.mvc.Results.*;
import static play.test.Helpers.*;
public class ApplicationControllerTest extends WithApplication {
static int FAKE_SERVICE_PORT = 7070;
Server server;
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.configure("externalSystem.port", FAKE_SERVICE_PORT)
.configure("externalSystem.host", "localhost")
.build();
}
@Before
public void setup() {
Router router = new RoutingDsl()
.GET("/b/1/").routeTo(() ->
// Request for branch information
ok().sendResource("externalSystem/getBranch.json")
)
.GET("/b/1/a/19033/").routeTo(() ->
// Request generating an already arrived appointment
ok().sendResource("externalSystem/arrivedAppointment.json")
)
.GET("/b/1/a/19962/").routeTo(() ->
// Request generating a newly created appointment
ok().sendResource("externalSystem/createdAppointment.json")
)
.build();
server = Server.forRouter(router, FAKE_SERVICE_PORT);
}
@After
public void tearDown() throws Exception {
server.stop();
}
@Test
public void AppCtrl() throws Exception {
// // These values are defined in the json files
String customerName = "Test User";
String branchName = "Test Branch";
RequestBuilder request = new RequestBuilder().method(GET).uri("/1/19962");
Result result = route(app, request);
assertEquals(OK, result.status());
assertTrue(contentAsString(result).contains(customerName));
assertTrue(contentAsString(result).contains(branchName));
}
}
However running this test with sbt test produces an IllegalStateException:
[error] Test controllers.ApplicationControllerTest.AppCtrl failed: java.lang.IllegalStateException: Attempted to call materialize() after the ActorMaterializer has been shut down., took 4.165 sec
[error] at akka.stream.impl.ActorMaterializerImpl.materialize(ActorMaterializerImpl.scala:164)
[error] at akka.stream.impl.ActorMaterializerImpl.materialize(ActorMaterializerImpl.scala:146)
[error] at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:350)
[error] at play.api.libs.streams.DoneAccumulator.run(Accumulator.scala:161)
[error] at play.api.test.EssentialActionCaller$class.call(Helpers.scala:225)
[error] at play.api.test.Helpers$.call(Helpers.scala:382)
[error] at play.api.test.RouteInvokers$class.route(Helpers.scala:247)
[error] at play.api.test.Helpers$.route(Helpers.scala:382)
[error] at play.api.test.RouteInvokers$class.jRoute(Helpers.scala:234)
[error] at play.api.test.Helpers$.jRoute(Helpers.scala:382)
[error] at play.api.test.Helpers.jRoute(Helpers.scala)
[error] at play.test.Helpers.route(Helpers.java:360)
[error] at play.test.Helpers.route(Helpers.java:355)
[error] at controllers.ApplicationControllerTest.AppCtrl(ApplicationControllerTest.java:63)
[error] ...
[error] Failed: Total 1, Failed 1, Errors 0, Passed 0
[error] Failed tests:
[error] controllers.ApplicationControllerTest
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful
I guess I could implement a completely standalone server to mock the service, but I would much rather not have the tests rely on a separate server.
So my question is this: Has anyone done someting similar with Play, and in that case what have I done wrong?