Documentation

You are viewing the documentation for the 2.4.2 release in the 2.4.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 Activator 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 included in your project build to assist you in using mocks.

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. Play also rewrites field accesses to use the generated getters/setters. Ebean relies on calls to the setters to do dirty checking. In order to use these patterns in JUnit tests, you will need to enable Play’s field access rewriting in test by adding the following to build.sbt:

compile in Test <<= PostCompile(Test)

You may also need the following import at the top of your build.sbt:

import play.Play._

§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.GET;
import static play.test.Helpers.contentAsString;
import static play.test.Helpers.route;
import javaguide.tests.controllers.Application;

import java.util.ArrayList;

import com.google.common.collect.ImmutableMap;
import org.junit.Test;

import play.mvc.Result;
import play.test.FakeApplication;
import play.test.Helpers;
import play.test.WithApplication;
import play.twirl.api.Content;

public class ApplicationTest extends WithApplication {
  
  @Override
  protected FakeApplication provideFakeApplication() {
    return new FakeApplication(new java.io.File("."), Helpers.class.getClassLoader(),
        ImmutableMap.of("play.http.router", "javaguide.tests.Routes"), new ArrayList<String>(), null);
  }

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

}

You can also retrieve an action reference from the reverse router and invoke it. This also allows you to use FakeRequest which is a mock for request data:

@Test
public void testCallIndex() {
  Result result = route(
    controllers.routes.Application.index(),
  );
  assertEquals(OK, result.status());
}

§Unit testing view templates

As a template is a standard Scala function, you can execute it from a test and check the result:

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

Next: Writing functional tests