Using an in-memory database for tests

You now have all the required knowledge to make your web service persistent. Once you have chosen a database technology, select the Play plugins you need (JDBC, JPA, and so on), configure your data sources right from your application.conf file, use the database helper classes provided by the plugins to integrate with your database technology, and finally implement your business layer on top of your database layer.

Once you have made your business layer persistent, you probably want to run your tests to check whether you introduced a regression. However, you will unexpectedly get the following error:

[info] A Shop should
[info] ! add items
[error]    RuntimeException: : There is no started application  (Play.scala:71)

What happened? Remember that your database configuration is read by your Play application at startup and then used by your database layer. The key step is when you retrieve the data source—remember that the method takes an implicit parameter of type Application as a parameter and that you supply the currently running application by using the Play singleton object. However, when running tests, Play does not start your application, so the Play singleton object throws an error when you try to retrieve the currently running application.

To fix the problem, you have to run a fake application as previously explained. However, you might want to run your tests on a database that is different from the production database. You can do this by passing custom configuration settings to your fake application, thus overriding the settings found in the application.conf file:

import play.api.test.{Helpers, FakeApplication, WithApplication}
class ShopSpec extends Specification {
  "A Shop" should {
    "add items" in new WithApplication(FakeApplication(additionalConfiguration = Helpers.inMemoryDatabase())) {
      Shop.create("foo", 42) must beSome[Item].which {
        item => item.name == "Play Framework Essentials" && item.price == 42
      }
    }
  }
}

The WithApplication constructor takes an application as a parameter, which defaults to a value of type FakeApplication. In the preceding code, we supply our own value of type FakeApplication that is configured to use an in-memory H2 database.

Note

You can use an H2 in-memory database even if your SQL scripts are written for another database, such as MySQL or PostgreSQL. Indeed, H2 has a compatibility layer for most relational database systems. For instance, you can ask H2 to use MySQL compatibility as follows:

inMemoryDatabase(options = Map("MODE" -> "MySQL"))

Now your tests should run! Before executing each test, Play makes a fake application using the supplied configuration. This configuration defines a data source, so the evolution plugin will detect evolution scripts and apply them to your testing database. After the test execution, the database is dropped.

In Java, the JDBC and JPA plugins also retrieve the currently running application using the Play singleton, so you have to start a fake application too:

public class ShopTest {
  @Test
  public void addItem() {
    running(fakeApplication(inMemoryDatabase()), () -> {
      Item item = Shop.create("Play Framework Essentials", 42.0);
      assertNotNull(item);
      assertEquals("Play Framework Essentials", item.name);
      assertEquals(new Double(42.0), item.price);
    });
  }
}

The inMemoryDatabase helper, as its name suggests, returns a configuration setting to use an in-memory database.

If most of your tests require a running application, you can avoid writing the running(…) statement at the beginning of each test by using the play.test.WithApplication class:

import play.test.WithApplication;
public class ShopTest extends WithApplication {
  @Override
  protected FakeApplication provideFakeApplication() {
    return fakeApplication(inMemoryDatabase());
  }
  @Test
  public void addItem() {
    Item item = Shop.create("Play Framework Essentials", 42.0);
    assertNotNull(item);
    assertEquals("Play Framework Essentials", item.name);
    assertEquals(new Double(42.0), item.price);
  }
}

The WithApplication class defines the JUnit setup and teardown methods that start an application before each test and stop after each test. You can customize the fake application to be used by overriding the provideFakeApplication method, as in the preceding code where I set up a fake application using an in-memory database.

Note that if you defined a custom global object as previously described, this global object will be used by your fake application. If you want to use distinct global settings in the test and development environments (for instance, in order to skip fixture data insertion), you can supply another global object to your fake application:

FakeApplication(withGlobal = Some(DefaultGlobal),additionalConfiguration = Helpers.inMemoryDatabase())

The Java equivalent code is as follows:

fakeApplication(inMemoryDatabase(), fakeGlobal())
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.186.167