§Writing functional tests
Play provides a number of classes and convenience methods that assist with functional testing. Most of these can be found either in the play.test
package or in the Helpers
class.
You can add these methods and classes by importing the following:
import play.test.*;
import static play.test.Helpers.*;
§FakeApplication
Play frequently requires a running Application
as context: it is usually provided from play.Play.application()
.
To provide an environment for tests, Play provides a FakeApplication
class which can be configured with a different Global object, additional configuration, or even additional plugins.
Application fakeApp = Helpers.fakeApplication();
Application fakeAppWithGlobal = fakeApplication(new GlobalSettings() {
@Override
public void onStart(Application app) {
System.out.println("Starting FakeApplication");
}
});
Application fakeAppWithMemoryDb = fakeApplication(inMemoryDatabase("test"));
§Injecting tests
If you’re using Guice for dependency injection then an Application
for testing can be built directly, instead of using FakeApplication. You can also inject any members of a test class that you might need. It’s generally best practice to inject members only in functional tests and to manually create instances in unit tests.
@Inject Application application;
@Before
public void setup() {
Module testModule = new AbstractModule() {
@Override
public void configure() {
// Install custom test binding here
}
};
GuiceApplicationBuilder builder = new GuiceApplicationLoader()
.builder(new Context(Environment.simple()))
.overrides(testModule);
Guice.createInjector(builder.applicationModule()).injectMembers(this);
}
@After
public void teardown() {
Helpers.stop(application);
}
§Testing with an application
To run tests with an Application
, you can do the following:
@Test
public void findById() {
running(fakeApplication(inMemoryDatabase("test")), () -> {
Computer macintosh = Computer.findById(21l);
assertEquals("Macintosh", macintosh.name);
assertEquals("1984-01-24", formatted(macintosh.introduced));
});
}
You can also extend WithApplication
, this will automatically ensure that an application is started and stopped for you:
public class FunctionalTest extends WithApplication {
This will ensure that a FakeApplication
will be started and stopped for each test method.
§Testing with a Guice application
To run tests with an Application
created by Guice, you can do the following:
@Test
public void findById() {
ClassLoader classLoader = classLoader();
Application application = new GuiceApplicationBuilder()
.in(new Environment(new File("path/to/app"), classLoader, Mode.TEST))
.build();
running(application, () -> {
Computer macintosh = Computer.findById(21l);
assertEquals("Macintosh", macintosh.name);
assertEquals("1984-01-24", macintosh.introduced);
});
}
Note that there are different ways to customize the Application
creation when using Guice to test.
§Testing with a server
Sometimes you want to test the real HTTP stack from within your test. You can do this by starting a test server:
@Test
public void testInServer() {
running(testServer(3333), () -> {
assertEquals(OK, WS.url("http://localhost:3333").get().get(timeout).getStatus());
});
}
Just as there exists a WithApplication
class, there is also a WithServer
which you can extend to automatically start and stop a TestServer
for your tests:
public class ServerFunctionalTest extends WithServer {
@Test
public void testInServer() {
int timeout = 5000;
String url = "http://localhost:" + this.testServer.port() + "/";
assertEquals(NOT_FOUND, WS.url(url).get().get(timeout).getStatus());
}
}
§Testing with a browser
If you want to test your application from with a Web browser, you can use Selenium WebDriver. Play will start the WebDriver for you, and wrap it in the convenient API provided by FluentLenium.
@Test
public void runInBrowser() {
running(testServer(), HTMLUNIT, browser -> {
browser.goTo("/");
assertEquals("Welcome to Play!", browser.$("#title").getText());
browser.$("a").click();
assertEquals("/login", browser.url());
});
}
And, of course there, is the WithBrowser
class to automatically open and close a browser for each test:
public class BrowserFunctionalTest extends WithBrowser {
@Test
public void runInBrowser() {
browser.goTo("/");
assertNotNull(browser.$("title").getText());
}
}
§Testing the router
Instead of calling the Action
yourself, you can let the Router
do it:
import play.mvc.Http.RequestBuilder;
@Test
public void testBadRoute() {
RequestBuilder request = new RequestBuilder()
.method(GET)
.uri("/xx/Kiwi");
Result result = route(request);
assertEquals(NOT_FOUND, result.status());
}
Next: Testing with Guice