Search code examples
playframeworkslickscalatest

Use different in-memory database for every test run


I have a Play application with some tests touching a database. For this, I configured Slick to use a separate in-memory H2 instance during test runs, something like:

slick.dbs.default.db.url="jdbc:h2:mem:play-test"

Now, ScalaTest executes suites in parallel, which generally shouldn't be a problem since the Play app is re-created for every suite. However, all of them touch the same database, potentially leading to unexpected states and causing tests to fail.

It works well when run locally, but fails on a CI server with the log indicating that test execution order is different, which in itself shouldn't be a problem if not parallel, but the database state at the beginning of one test is not as expected.

Now, one solution I would be to run those suites sequentially using Sequential.

But in my opinion it would be nices to still be able to run them in parallel, but with different databases, something like:

slick.dbs.default.db.url="jdbc:h2:mem:play-test-${UUID.generate()}"

Above syntax is entirely made up, but is something like UUID (or some other random string) generation supported in Play config files?


Solution

  • Thanks to marcospereira's comment I ended up creating a trait customizing my in-mem H2 name with a random suffix:

    trait FreshDatabase extends GuiceOneAppPerSuite {
      this: TestSuite =>
    
      val BaseName = "play-test"
      val UrlConfigKey = "slick.dbs.default.db.url"
    
      override def fakeApplication(): Application = {
        val defaultUrl = super.fakeApplication().configuration.get[String](UrlConfigKey)
    
        val random = Random.nextInt(Integer.MAX_VALUE)
        val freshUrl = defaultUrl.replace(BaseName, s"$BaseName-$random")
    
        GuiceApplicationBuilder().configure(UrlConfigKey -> freshUrl).build()
      }
    }
    

    Then use it in relevant test suites, e.g.:

    class AnswerControllerSpec extends PlaySpec
      with GuiceOneAppPerSuite with FreshDatabase {
      // ...
    }
    

    My application.conf (as before):

    slick.dbs.default.profile="slick.jdbc.H2Profile$"
    slick.dbs.default.db.driver="org.h2.Driver"
    slick.dbs.default.db.url="jdbc:h2:mem:play-test"