在 play 2.4 和 Slick 3 中为单元测试设置内存数据库时遇到问题

Having Trouble setting up in memory db for unit tests in play 2.4 an Slick 3

我正在尝试在内存中设置一个 h2 数据库,然后使用 Slicks 功能创建必要的表,以用于我的 play specs2 测试。我已经创建了一个抽象 class 覆盖 WithApplication 然后覆盖 around 方法但是当 createTables 函数尝试 运行 预测试时我得到一个错误。我怀疑我没有正确传递数据库连接/配置,但我得到的错误不是很有帮助。我正在通过包装播放 Databases.withInMemory 函数

创建数据库

这是我的数据库助手对象

package testHelpers

import models.VisitorImages._
import models.VisitorRegistrations._
import models.VisitorSignatures._
import models.VisitorStatuses._
import models.Visitors._
import org.specs2.execute.{Result, AsResult}
import play.api.test.WithApplication
import play.api.{Logger, Application, Play}
import play.api.db.slick.DatabaseConfigProvider
import play.api.db.{Databases, Database}
import slick.backend.DatabaseConfig
import slick.profile.{BasicProfile, RelationalProfile}

import scala.concurrent.Await
import scala.concurrent.duration.Duration

object TestDatabase {
  class testDbProvider extends DatabaseConfigProvider {
    def get[P <: BasicProfile]: DatabaseConfig[P] = {
      DatabaseConfigProvider.get("default")(Play.current)
    }
  }

  def startTestDb[T](block: Database => T) = {
    Databases.withInMemory(
      name = "testDB",
      urlOptions = Map(
        "MODE" -> "MSSQLServer"
      ),
      config = Map(
        "logStatements" -> true
      )
    )(block)
  }

  abstract class WithTestDb extends WithApplication((TestApplication.application)) {
    val profile = slick.driver.H2Driver
    import profile.api._

    override def around[T: AsResult](t: => T): Result = super.around {
      setupData()
      t
    }

    val allTables = (VisitorSignatures.schema ++ VisitorImages.schema ++ Visitors.schema ++ VisitorStatuses.schema ++ VisitorRegistrations.schema
    ).create

    /** Create all tables in database */
    def createTables = {
      Logger.info(s"yadda yadda yadda")
      val db = new testDbProvider().get.db
      Await.result(db.run(Visitors.schema.create), Duration.Inf)
      Logger.info(s"variable user is blah blah")
    }

    /** Delete all tables in database */
    def drop = {
//      allTables.drop
    }

    def setupData() {
      // setup data
      createTables
    }
  }

}

这是我尝试使用它的方式

package unit.models

import models.VisitorRegistrations._
import play.api.{Play, db}
import play.api.db.slick.DatabaseConfigProvider
import play.api.test.{WithApplication, PlaySpecification}
import play.db.NamedDatabase
import providers.VisitorRegistrationProvider
import repositories.VisitorRegistrationRepository
import slick.driver.JdbcProfile
import slick.lifted.TableQuery
import testHelpers.TestDatabase.WithTestDb
import testHelpers.{Inject, TestApplication, TestDatabase}

import scala.concurrent.Await
import scala.concurrent.duration.Duration

class VisitorRegistrationsSpec extends PlaySpecification with Inject {
  val vrp = inject[VisitorRegistrationProvider]
  val db = vrp.dbConfig.db

  import vrp.dbConfig.driver.api._

  TestDatabase.startTestDb { database =>
    "VisitorResgistrations" should {
      "save a vr" in new WithTestDb {

        val res = Await.result(db.run(VisitorRegistrations.result), Duration.Inf)

        res must equalTo(1)
      }
    }

  }
}

这是我得到的错误

[info] VisitorResgistrations should
[error]   ! save a vr
[error]    null (Database.scala:61)
[error] testHelpers.TestDatabase$WithTestDb.createTables(Database.scala:61)
[error] testHelpers.TestDatabase$WithTestDb.setupData(Database.scala:72)
[error] testHelpers.TestDatabase$WithTestDb$$anonfun$around.apply(Database.scala:50)
[error] play.api.test.WithApplication$$anonfun$around.apply(Specs.scala:39)
[error] play.api.test.WithApplication$$anonfun$around.apply(Specs.scala:39)
[error] play.api.test.PlayRunners$class.running(Helpers.scala:42)
[error] play.api.test.Helpers$.running(Helpers.scala:363)
[error] play.api.test.WithApplication.around(Specs.scala:39)
[error] testHelpers.TestDatabase$WithTestDb.around(Database.scala:49)
[error] play.api.test.WithApplication.delayedInit(Specs.scala:36)
[error] testHelpers.TestDatabase$WithTestDb.<init>(Database.scala:45)
[error] unit.models.VisitorRegistrationsSpec$$anonfun$$anonfun$apply$$anonfun$apply$$anon.<init>(VisitorRegistrationsSpec.scala:30)
[error] unit.models.VisitorRegistrationsSpec$$anonfun$$anonfun$apply$$anonfun$apply.apply(VisitorRegistrationsSpec.scala:30)
[error] unit.models.VisitorRegistrationsSpec$$anonfun$$anonfun$apply$$anonfun$apply.apply(VisitorRegistrationsSpec.scala:30)

Off-hand,看来你的初始化顺序有问题。尝试将 class-level val 更改为 lazy valdef.