代码之家  ›  专栏  ›  技术社区  ›  SkyWalker

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

  •  1
  • SkyWalker  · 技术社区  · 8 年前

    我正在努力 this github project 它使用Play 2.5.10和Slick 3.1.1(可以通过运行 sbt test 但是可以 also be checked directly in travis CI ). 我使用Postgres数据库配置 default 用于开发和生产。然后我使用一个名为H2的内存数据库 test 用于测试。这个 违约 数据库是在中配置的 conf/application.conf 鉴于 测验 数据库是在中配置的 conf/application.test.conf .

    问题是,对于测试,我使用名称初始化数据库 测验 但是,应用程序是用 GuiceApplicationBuilder 仍在收集 违约

    这条线在我的 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仍然尝试连接到 违约 数据库

    1 回复  |  直到 8 年前
        1
  •  3
  •   Paul Dolega    8 年前

    好吧,你的问题有点不同(或者可能有点出乎意料)。这是导致您头痛的一行:

    dbApi.databases().foreach(runEvolutions)
    

    其在: ApplicationEvolutions.scala:42

    这可能是不言而喻的:)

    然而,问题更加复杂。测试环境中实际上有两个数据库( default test ). 现在,这导致了几个问题,其中一个问题您可以在上面看到(在每个问题上都尝试了进化)。另一个原因是,如果你想使用不同名称的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=""
      }
    }
    

    现在唯一的问题是你应该有一组进化( 违约 )这实际上并没有那么糟糕,因为它可以确保测试数据库与生产数据库同步(至少在结构方面)。

    这并不是说以上是唯一的解决方案。您仍然可以有两种不同名称的db配置;在这种情况下,您需要在应用程序中进行某种重新映射 Guilce module (然后,您将有一个用于prod的模块和一个用于test的模块——它们可以相互继承,只覆盖某些内容——例如,附加) 测验 db代替默认值)。这基本上是一个品味的问题。