How to apply play-evolutions when running tests in

2019-06-16 07:51发布

问题:

I have problems with evolutions when running tests in play framework using

  • playframework v2.6.6 for scala
  • play-slick v3.0.2
  • play-slick-evolutions v3.0.2

The test looks like this:

class TestFooController extends PlaySpec with GuiceOneServerPerSuite {
  "foo endpoint should store some data" in {
    val wsClient = app.injector.instanceOf[WSClient]
    val url = s"http://localhost:$port/foo"
    val requestData = Json.obj("foo" -> "bar")
    val response = await(wsClient.url(url).post(requestData))
    response.status mustBe OK
  }
}

The database configuration looks like this:

slick.dbs.default.driver="slick.driver.H2Driver$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:play"

Asume there is an evolution script which creates the table foos and this script is working fine in dev mode.

When running the test the following error is thrown:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[JdbcSQLException: Table "foos" not found;

The table foos could not be found so I assume that database evolutions have not been applied.

Then I changed the database configuration to postgresql which is used in dev mode.

slick.dbs.default.driver = "slick.driver.PostgresDriver$"
slick.dbs.default.db.driver = "org.postgresql.Driver"
slick.dbs.default.db.url = "jdbc:postgresql://localhost:5432/foo-test"
slick.dbs.default.db.user = "user"
slick.dbs.default.db.password = "password"

With this configuration the test work fine and data are stored in the database, so database evolutions ran just fine.

Now the problem is, that the database is not cleaned up after tests. I'd like to run each test suite with a clean database.

To sum up. With H2Db evolutions are not applied, with postgresql evolutions are applied but not cleaned up.

Even if this explicitly defined in application.test.conf

play.evolutions.autoApply=true
play.evolutions.autoApplyDowns=true

I also tried

play.evolutions.db.default.autoApply=true
play.evolutions.db.default.autoApplyDowns=true

no effect.

Then I tried to do this manually via:

  def withManagedDatabase[T](block: Database => T): Unit = {
    val dbapi    = app.injector.instanceOf[DBApi]
    val database = dbapi.database("default")
    Evolutions.applyEvolutions(database)
    block(database)
    Evolutions.cleanupEvolutions(database)
  }

and then changing the test to:

  "foo endpoint should store some data" in withManagedDatabase { _ =>
    ...
  }

For the H2 database configuration it has no effect, the same error that table foos can not be found is thrown. For the postgresql database configuration an evolution exceptions is thrown

play.api.db.evolutions.InconsistentDatabase: Database 'default' is in an inconsistent state![An evolution has not been applied properly. Please check the problem and resolve it manually before marking it as resolved.]

I want evolution ups running before and evolution downs running after each test suite. How can this be achieved?

回答1:

This is working for me:

class DAOSpec extends PlaySpec with GuiceOneAppPerSuite {

  val dbUrl = sys.env.getOrElse("DATABASE_URL", "postgres://foo:password@localhost:5432/foo")

  val testConfig = Map("db.default.url" -> dbUrl)

  implicit override def fakeApplication() = new GuiceApplicationBuilder().configure(testConfig).build()

  lazy val database = app.injector.instanceOf[Database]
  lazy val dao = app.injector.instanceOf[DAO]

  "create" must {
    "work" in Evolutions.withEvolutions(database) {
      val foo = await(dao.create("foo"))
      foo.id must not be null
    }
  }

}