GuiceApplicationBuilder->运行测试时尝试访问prod db的演进

时间:2018-06-22 14:12:09

标签: unit-testing guice playframework-evolutions

我们正在使用

  • Scala 2.12.5
  • 玩2.6.14进行进化
  • 光滑3.2.3
  • 在IntelliJ 2018.1的多模块项目中

在子项目“服务”中,我们(想要)使用Guice在用于产品的 MySql 和用于单元测试的 H2 之间切换。 这在过去是可行的,但现在我们也使用进化来产生问题。

我们的 application.conf 文件包含一些进行演变的行:

db.default = {
  driver="com.mysql.jdbc.Driver"
  url="jdbc:mysql://localhost:3306/dev"
  url=${?rds.url}
  username="dev-user"
  username= ${?rds.user}
  password="<secret>"
  password=${?rds.password}
}

一个示例测试类如下

class HomeControllerTest extends PlaySpec with GuiceOneAppPerTest with BeforeAndAfterAll {

  val application: play.api.Application = new GuiceApplicationBuilder()
    .in(Mode.Test)
    .overrides(
      bind[DbComponent].to(classOf[H2DbComponent])
    ).build()

  // the same for:
  override def fakeApplication(): Application = new GuiceApplicationBuilder()...

  // the same for:
  implicit override lazy val app: play.api.Application = new GuiceApplicationBuilder()...

问题: 运行使用Guice的测试类时,Evolution尝试访问“默认” MySql数据库。这不是故意的,并且在Jenkins上运行时将使测试失败。 当'db.default = {...}'行被注释掉时,测试运行正常。

为解决此问题,我们还有一个替代的 conf / application.test.conf 文件,其中包含用于覆盖“默认”数据库设置的行:

db.default = {
  driver = "org.h2.Driver"
  url = "jdbc:h2:mem:h2test;MODE=MySql;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS dev_db"
}

并在 service / build.sbt 行中添加

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

事实证明,Guice不使用备用配置文件 application.test.conf 。可以通过分析 play.api.db.DBApiProvider :: get 中的“ configuration”的值来验证。

为了克服这个问题,测试类现在看起来像

class HomeControllerTest extends PlaySpec with GuiceOneAppPerTest with BeforeAndAfterAll {

  val configuration: Configuration = Configuration.reference ++ Configuration(ConfigFactory.parseResources("application.test.conf").resolve)

  val application: play.api.Application = new GuiceApplicationBuilder()
    .in(Mode.Test)
    .loadConfig(configuration)
    .overrides(
      bind[DbComponent].to(classOf[H2DbComponent])
    ).build()

这会产生错误:

Exception encountered when invoking run on a nested suite - Guice configuration errors:

1) No implementation for play.api.Application was bound.
  while locating play.api.Application

1 error
com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for play.api.Application was bound.
  while locating play.api.Application

1 error
    at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1045)
    at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
    at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054)
    at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:409)
    at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:404)
    at play.api.inject.ContextClassLoaderInjector.$anonfun$instanceOf$2(Injector.scala:117)
    at play.api.inject.ContextClassLoaderInjector.withContext(Injector.scala:126)
    at play.api.inject.ContextClassLoaderInjector.instanceOf(Injector.scala:117)
    at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:137)
    at controllers.HomeControllerTest.fakeApplication(HomeControllerTest.scala:36)
    at org.scalatestplus.play.BaseOneAppPerSuite.app(BaseOneAppPerSuite.scala:29)
    at org.scalatestplus.play.BaseOneAppPerSuite.app$(BaseOneAppPerSuite.scala:29)
    at controllers.HomeControllerTest.app$lzycompute(HomeControllerTest.scala:22)
    at controllers.HomeControllerTest.app(HomeControllerTest.scala:22)
    at org.scalatestplus.play.BaseOneAppPerSuite.run(BaseOneAppPerSuite.scala:42)
    at org.scalatestplus.play.BaseOneAppPerSuite.run$(BaseOneAppPerSuite.scala:41)
    at controllers.HomeControllerTest.org$scalatest$BeforeAndAfterAll$$super$run(HomeControllerTest.scala:22)
    at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:213)
    at org.scalatest.BeforeAndAfterAll.run(BeforeAndAfterAll.scala:210)
    at org.scalatest.BeforeAndAfterAll.run$(BeforeAndAfterAll.scala:208)
    at controllers.HomeControllerTest.run(HomeControllerTest.scala:22)
    at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
    at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13(Runner.scala:1346)
    at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13$adapted(Runner.scala:1340)
    at scala.collection.immutable.List.foreach(List.scala:389)
    at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1340)
    at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24(Runner.scala:1031)
    at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24$adapted(Runner.scala:1010)
    at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1506)
    at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
    at org.scalatest.tools.Runner$.run(Runner.scala:850)
    at org.scalatest.tools.Runner.run(Runner.scala)
    at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2(ScalaTestRunner.java:131)
    at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:28)

作为该问题的解决方法,我将 application.conf 中数据库 default 的所有连接数据默认值更改为H2期望的值:

// DB connect information - needed for Play Evolutions
db.default = {
  driver="org.h2.Driver"   // value needed for testing on Jenkins (with H2)
  driver=${?rds.driver}    // for dev / stage / prod ->"com.mysql.jdbc.Driver"

  url="jdbc:h2:mem:h2test;MODE=MySql;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS dev_db" // for testing on Jenkins (H2)
  url=${?rds.url}         // for dev / stage / prod -> "jdbc:mysql://localhost:3306/<schema-name>"

  username=""              // value needed for testing on Jenkins (with H2)
  username=${?rds.user}
  password=""              // value needed for testing on Jenkins (with H2)
  password=${?rds.password}
}

play.evolutions.enabled=false  // value needed for testing on Jenkins (with H2) - evolutions must be disabled
play.evolutions.enabled=${?VALUE}  // set to "true" for 'dev' and 'stage'

但是,用于处理内存中测试数据库演化的干净,建议和可行的解决方案是什么?

非常感谢

0 个答案:

没有答案