测试Scala Play + Slick:为什么选择错误的数据库?

时间:2016-12-29 19:51:02

标签: scala playframework slick

我正在处理使用Play 2.5.10和Slick 3.1.1的this github project(可以通过运行sbt test来重现该问题,但可以also be checked directly in travis CI)。我使用Postgres数据库配置default进行开发和生产。然后我在名为test的内存数据库中使用H2进行测试。 default数据库在conf/application.conf中配置,而test数据库在conf/application.test.conf中配置。

问题是,对于测试,我使用名称test初始化数据库,但使用GuiceApplicationBuilder构建的应用程序仍在使用default

此行在我的build.sbt中以获取测试配置:

javaOptions in Test += "-Dconfig.file=conf/application.test.conf"

这是该文件的内容:

include "application.conf"

slick.dbs {
  test {
    driver="slick.driver.H2Driver$"
    db.driver="org.h2.Driver"
    db.url="jdbc:h2:mem:test;MODE=PostgreSQL"
    db.username="sa"
    db.password=""
  }
}

我的DaoFunSpec基类看起来像这样:

package dao

import org.scalatest.{BeforeAndAfterAll, FunSpec}
import org.scalatestplus.play.OneAppPerSuite
import play.api.Application
import play.api.db.evolutions.Evolutions
import play.api.db.DBApi

abstract class DaoFunSpec extends FunSpec with OneAppPerSuite with BeforeAndAfterAll {
  lazy implicit val db = app.injector.instanceOf[DBApi].database("test")

  override def beforeAll() {
    Evolutions.applyEvolutions(db)
  }

  override def afterAll() {
    Evolutions.cleanupEvolutions(db)
  }

  def userDao(implicit app: Application) = {
    Application.instanceCache[UserDao].apply(app)
  }
}

注意第app.injector.instanceOf[DBApi].database("test")行,但Play仍尝试连接default数据库。

1 个答案:

答案 0 :(得分:3)

好的,你的问题有点不同(或者可能有点意外)。这是引起你头痛的因素:

dbApi.databases().foreach(runEvolutions)

它位于:ApplicationEvolutions.scala:42

这可能是不言自明的:)

问题仍然存在。实际上,您的测试环境中有两个数据库(defaulttest)。现在这会导致一些问题 - 您在上面看到了其中一个问题(每个问题都在尝试进化)。另一个是如果你想使用不同名称的db,你不能只注入类似的东西:

class UserDao @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)

相反,你需要使用(AFAIR):

class UserDao @Inject()(@NamedDatabase("test") protected val dbConfigProvider: DatabaseConfigProvider)

但在这种情况下,你的测试变得更加复杂。

如果出现以下情况会更简单:

1)您可以将常用配置提取到common.conf

2)您可以将application.conf更改为以下内容:

include "common.conf"

slick.dbs {
  default {
    driver="slick.driver.PostgresDriver$"
    db.driver="org.postgresql.Driver"
    db.url="jdbc:postgresql://localhost:5432/exampledb?searchpath=public"
    db.user="postgres"
    db.password="postgres"
  }
}

3)您可以将application.test.conf更改为以下内容:

include "common.conf"

slick.dbs {
  default {
    driver="slick.driver.H2Driver$"
    db.driver="org.h2.Driver"
    db.url="jdbc:h2:mem:test;MODE=PostgreSQL"
    db.username="sa"
    db.password=""
  }
}

现在唯一的事情就是你应该有一套演变(default),这实际上并没有那么糟糕,因为它会确保你的测试数据库与你的生产数据库同步(至少在术语上)结构)。

上述并不是唯一的解决方案。你仍然可以有两个不同命名的db配置;你需要在这种情况下在你的Guilce module中进行某种重新映射(然后你会有一个模块用于prod,一个用于测试 - 它们可以相互继承并且只覆盖某些东西 - 例如附加{{ 1}} db代替默认值1)。这基本上是一种品味问题。