Cup of Java

Tales of a lost software developer

Fast and Reliable Integration Tests With Play 2

When you start using the Play Framework 2 you will notice that there are a bunch of test helpers and entry points to set up your tests. That’s great! One might thinks that’s too good to be true. And in fact, when using the FakeApplication test helper you can run into subtle problems which cause unreliable tests.

In the Play Framework documentation they show you that it is quite easy to set up a test with a FakeApplication by the following code snippet:

Example of FakeApplication usage in Play Framework documentation
1
2
3
4
5
6
7
8
9
10
@Test
public void findById() {
  running(fakeApplication(), new Runnable() {
    public void run() {
      Computer macintosh = Computer.find.byId(21l);
      assertThat(macintosh.name).isEqualTo("Macintosh");
      assertThat(formatted(macintosh.introduced)).isEqualTo("1984-01-24");
    }
  });
}

So, you might think when you have many test methods you just copy this pattern and everything is fine. But that is not the case!

Pattern of FakeApplication per test method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void testOne() {
  running(fakeApplication(), new Runnable() {
    public void run() {
      // test logic
    }
  });
}

@Test
public void testTwo() {
  running(fakeApplication(), new Runnable() {
    public void run() {
      // test logic
    }
  });
}

Here are two examples that FakeApplication can be difficult to use:

I ran into the same problems that are mentioned in the first mailinglist posting. In the project where I’m using MongoDB together with Play 2 the tests with a FakeApplication started to become unreliable. There were issues with cleaning up test data after and before each test method. Also the shutdown and restart of a FakeApplication was sometimes error prone.

The best solution for this problems is to start one FakeApplication per test class, not per test method. Here is the test helper class that I use for this:

One FakeApplication per test class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import play.test.FakeApplication;

import static play.test.Helpers.*;

public abstract class AbstractOneFakeApplicationIntegrationTest {

    private static FakeApplication fakeApplication;

    @BeforeClass
    public static void startFakeApplication() {
        fakeApplication = fakeApplication();
        start(fakeApplication);
    }

    @AfterClass
    public static void shutdownFakeApplication() {
        stop(fakeApplication);
    }
}

You only need to inherit from it and every test has access to a running FakeApplication. One disadvantage is that you have more work to clean up any data that is written for your tests into databases, filesystem or any other persistent system. But you get reliable integration tests and the tests are much faster because you only start one FakeApplication per class and not dozens of them as in the per method approach

Beside this little issues that FakeApplication can cause Play 2 offers great testing support.

Comments