Scala 在play框架中运行测试时如何应用play演进?

Scala 在play框架中运行测试时如何应用play演进?,scala,playframework,play-slick,playframework-evolutions,playframework-2.6,Scala,Playframework,Play Slick,Playframework Evolutions,Playframework 2.6,在play框架中使用 scala的playframework v2.6.6 播放slick v3.0.2 play slick evolutions v3.0.2 测试如下所示: class TestFooController extends PlaySpec with GuiceOneServerPerSuite { "foo endpoint should store some data" in { val wsClient = app.injector.instanceOf

在play框架中使用

  • scala的playframework v2.6.6
  • 播放slick v3.0.2
  • play slick evolutions v3.0.2
测试如下所示:

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
  }
}
slick.dbs.default.driver="slick.driver.H2Driver$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:play"
数据库配置如下所示:

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
  }
}
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有一个进化脚本,它创建了表
foos
,这个脚本在开发模式下运行良好

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"
运行测试时,会引发以下错误:

play.api.http.HttpErrorHandlerExceptions$$anon$1:执行异常[[jdbcsqleException:未找到表“foos;”

找不到表
foos
,因此我假设没有应用数据库演变

然后我将数据库配置更改为postgresql,它在开发模式下使用

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"
通过这种配置,测试工作正常,数据存储在数据库中,因此数据库的演进运行正常

现在的问题是,测试后数据库没有被清理。我想用一个干净的数据库运行每个测试套件

综上所述,对于H2Db,进化不被应用,对于postgresql,进化被应用但没有被清理

即使在
application.test.conf

play.evolutions.autoApply=true
play.evolutions.autoApplyDowns=true
我也试过了

play.evolutions.db.default.autoApply=true
play.evolutions.db.default.autoApplyDowns=true
没有效果

然后我尝试通过以下方式手动执行此操作:

  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)
  }
然后将测试更改为:

  "foo endpoint should store some data" in withManagedDatabase { _ =>
    ...
  }
对于H2数据库配置,它不起作用,抛出与找不到表
foos
相同的错误。对于postgresql数据库配置,抛出演化异常

play.api.db.evolutions.InconsistentDatabase:数据库“默认”处于不一致状态![未正确应用演化。请检查问题并手动解决,然后将其标记为已解决。]


我希望在每个测试套件之前运行evolution ups,在每个测试套件之后运行evolution downs。如何实现这一点?

这对我来说很有效:

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
    }
  }

}

您可以使用以下方法在每个套件之前应用演进,然后进行清理:

trait DatabaseSupport extends BeforeAndAfterAll {
  this: Suite with ServerProvider =>

  private lazy val db = app.injector.instanceOf[DBApi]

  override protected def beforeAll(): Unit = {
    super.beforeAll()
    initializeEvolutions(db.database("default"))
  }

  override protected def afterAll(): Unit = {
    cleanupEvolutions(db.database("default"))
    super.afterAll()
  }

  private def initializeEvolutions(database: Database):Unit = {
    Evolutions.cleanupEvolutions(database)
    Evolutions.applyEvolutions(database)
  }

  private def cleanupEvolutions(database: Database):Unit = {
    Evolutions.cleanupEvolutions(database)
  }

}


嗨,我也有同样的问题,你找到解决办法了吗?