Documentation

You are viewing the documentation for the 2.8.4 release in the 2.8.x series of releases. The latest stable release series is 3.0.x.

§Testing your application

Writing tests for your application can be an involved process. Play supports JUnit and provides helpers and application stubs to make testing your application as easy as possible.

§Overview

The location for tests is in the “test” folder. There are two sample test files created in the test folder which can be used as templates.

You can run tests from the sbt console.

Testing in Play is based on sbt, and a full description is available in the testing documentation.

§Using JUnit

The default way to test a Play application is with JUnit.

import static org.junit.Assert.*;

import org.junit.Test;

public class SimpleTest {

  @Test
  public void testSum() {
    int a = 1 + 1;
    assertEquals(2, a);
  }

  @Test
  public void testString() {
    String str = "Hello world";
    assertFalse(str.isEmpty());
  }
}

Note: A new process is forked each time test or test-only is run. The new process uses default JVM settings. Custom settings can be added to build.sbt. For example:

javaOptions in Test ++= Seq(
  "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9998",
  "-Xms512M",
  "-Xmx1536M",
  "-Xss1M",
  "-XX:MaxPermSize=384M"
)

§Assertions & Matchers

Some developers prefer to write their assertions in a more fluent style than JUnit asserts. Popular libraries for other assertion styles are included for convenience.

Hamcrest matchers:

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class HamcrestTest {

  @Test
  public void testString() {
    String str = "good";
    assertThat(str, allOf(equalTo("good"), startsWith("goo")));
  }
}

§Mocks

Mocks are used to isolate unit tests against external dependencies. For example, if your class under test depends on an external data access class, you can mock this to provide controlled data and eliminate the need for an external data resource.

The Mockito library is a popular mocking framework for Java. To use it in your tests add a dependency on the mockito-core artifact to your build.sbt file. For example:

libraryDependencies += "org.mockito" % "mockito-core" % "2.10.0" % "test"

You can find the current version number of mockito-core here.

Using Mockito, you can mock classes or interfaces like so:

import static org.mockito.Mockito.*;
// Create and train mock
List<String> mockedList = mock(List.class);
when(mockedList.get(0)).thenReturn("first");

// check value
assertEquals("first", mockedList.get(0));

// verify interaction
verify(mockedList).get(0);

§Unit testing models

Let’s assume we have the following data model:

public class User {
  private Integer id;
  private String name;

  public User(final Integer id, final String name) {
    this.id = id;
    this.name = name;
  }
}

public class Role {
  private String name;

  public Role(final String name) {
    this.name = name;
  }
}

Some data access libraries such as Ebean allow you to put data access logic directly in your model classes using static methods. This can make mocking a data dependency tricky.

A common approach for testability is to keep the models isolated from the database and as much logic as possible, and abstract database access behind a repository interface.

public interface UserRepository {
  public Set<Role> findUserRoles(User user);
}

public class UserRepositoryEbean implements UserRepository {
  @Override
  public Set<Role> findUserRoles(User user) {
    // Get roles from DB
     ...
  }
}

Then use a service that contains your repository to interact with your models:

public class UserService {
  private final UserRepository userRepository;

  public UserService(final UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  public boolean isAdmin(final User user) {
    final Set<Role> roles = userRepository.findUserRoles(user);
    for (Role role : roles) {
      if (role.name.equals("ADMIN")) return true;
    }
    return false;
  }
}

In this way, the UserService.isAdmin method can be tested by mocking the UserRepository dependency:

@Test
public void testIsAdmin() {

  // Create and train mock repository
  UserRepository repositoryMock = mock(UserRepository.class);
  Set<Role> roles = new HashSet<Role>();
  roles.add(new Role("ADMIN"));
  when(repositoryMock.findUserRoles(any(User.class))).thenReturn(roles);

  // Test Service
  UserService userService = new UserService(repositoryMock);
  User user = new User(1, "Johnny Utah");
  assertTrue(userService.isAdmin(user));
  verify(repositoryMock).findUserRoles(user);
}

Note: Applications using Ebean ORM may be written to rely on Play’s automatic getter/setter generation. If this is your case, check how Play enhancer sbt plugin works.

§Unit testing controllers

You can test your controllers using Play’s test helpers to extract useful properties.

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static play.mvc.Http.Status.OK;
import static play.test.Helpers.*;

import javaguide.tests.controllers.HomeController;

import org.junit.Test;

import play.mvc.Result;
import play.twirl.api.Content;

public class ControllerTest {

  @Test
  public void testIndex() {
    Result result = new HomeController().index();
    assertEquals(OK, result.status());
    assertEquals("text/html", result.contentType().get());
    assertEquals("utf-8", result.charset().get());
    assertTrue(contentAsString(result).contains("Welcome"));
  }

}

§Unit testing view templates

As a template is a just a method, you can execute it from a test and check the result:

@Test
public void renderTemplate() {
    Content html = views.html.index.render("Welcome to Play!");
  assertEquals("text/html", html.contentType());
  assertTrue(contentAsString(html).contains("Welcome to Play!"));
}

§Unit testing with Messages

If you need a play.i18n.MessagesApi instance for unit testing, you can use play.test.Helpers.stubMessagesApi() to provide one:

@Test
public void renderMessages() {
  Langs langs = new Langs(new play.api.i18n.DefaultLangs());

  Map<String, String> messagesMap = Collections.singletonMap("foo", "bar");
  Map<String, Map<String, String>> langMap =
      Collections.singletonMap(Lang.defaultLang().code(), messagesMap);
  MessagesApi messagesApi = play.test.Helpers.stubMessagesApi(langMap, langs);

  Messages messages = messagesApi.preferred(langs.availables());
  assertEquals(messages.at("foo"), "bar");
}

Next: Writing functional tests