尝试在 Scala 中为 Play Web 应用程序的 Slick 数据库创建单元测试

Posted

技术标签:

【中文标题】尝试在 Scala 中为 Play Web 应用程序的 Slick 数据库创建单元测试【英文标题】:Trying to create Unit tests for Slick database for Play web application in Scala 【发布时间】:2018-02-02 12:52:20 【问题描述】:

我正在努力尝试使用 Scala 为我的 Play Web 应用程序配置单元测试。我正在使用 Play 2.6 和 Scala 2.11.8。当我使用数据库配置并执行sbt test 时,我在控制台上收到错误No implementation for play.api.db.slick.DatabaseConfigProvider was bound。所以我将展示我如何设置我的网络应用程序,也许有人可以指出哪里出了问题。只是为了方便起见,Web 应用程序运行良好。这只是我无法创建的数据库的单元测试。

build.sbt

import play.sbt.PlayImport._

name := """crypto-miners-demo"""    
version := "1.0-SNAPSHOT"    
lazy val root = (project in file(".")).enablePlugins(PlayScala)    
scalaVersion := "2.11.8"

libraryDependencies += guice
libraryDependencies += evolutions
libraryDependencies += jdbc
libraryDependencies += filters
libraryDependencies += ws

libraryDependencies += "com.h2database" % "h2" % "1.4.194"
libraryDependencies += "com.typesafe.play" %% "anorm" % "2.5.3"
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.0" % Test

libraryDependencies += "com.typesafe.play" %% "play-slick" % "3.0.0"
libraryDependencies += "com.typesafe.play" %% "play-slick-evolutions" % "3.0.0"
libraryDependencies += "org.xerial" % "sqlite-jdbc" % "3.19.3"

libraryDependencies += "org.apache.spark" %% "spark-core" % "2.2.0"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.2.0"

dependencyOverrides += "com.fasterxml.jackson.core" % "jackson-databind" % "2.6.5"

application.conf:

play.application.loader = di.ApplicationLoader

play.filters.csrf.header.bypassHeaders 
  X-Requested-With = "*"
  Csrf-Token = "nocheck"

play.filters.csrf.bypassCorsTrustedOrigins = false
play.filters.disabled += play.filters.csrf.CSRFFilter

slick.dbs.default.profile = "slick.jdbc.SQLiteProfile$"
slick.dbs.default.db.driver = "org.sqlite.JDBC"
slick.dbs.default.db.url = "jdbc:sqlite:development.db"
slick.dbs.default.db.username = ""
slick.dbs.default.db.password = ""

db.default 
  driver = org.sqlite.JDBC
  url = "jdbc:sqlite:development.db"
  username = ""
  password = ""


play.modules.disabled += "play.api.db.DBModule"

RackRepositorySpec.scala:

import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.guice.GuiceOneAppPerTest
import play.api.db.evolutions._
import play.api.db.slick.DatabaseConfigProvider
import play.api.db.Database, Databases
import play.api.inject.bind
import play.api.inject.guice.GuiceInjectorBuilder
import play.api.test.Injecting

class RackRepositorySpec extends PlaySpec with GuiceOneAppPerTest with Injecting 

  val database = Databases(
    driver = "org.sqlite.JDBC",
    url = "jdbc:sqlite:development.db",
    name = "default",
    config = Map(
      "username" -> "",
      "password" -> ""
    )
  )
  val guice = new GuiceInjectorBuilder()
    .overrides(bind[Database].toInstance(database))
    .injector()
  val defaultDbProvider = guice.instanceOf[DatabaseConfigProvider]

  def beforeAll() = Evolutions.applyEvolutions(database)

  def afterAll() = 
    // Evolutions.cleanupEvolutions(database)
    database.shutdown()
  
  Evolution(
    1,
    "create table test (id bigint not null, name varchar(255));",
    "drop table test;"
  )

当我执行 sbt test 时出现此错误:

[info] models.RackRepositorySpec *** ABORTED ***
[info]   com.google.inject.ConfigurationException: Guice configuration errors:
[info] 
[info] 1) No implementation for play.api.db.slick.DatabaseConfigProvider was bound.
[info]   while locating play.api.db.slick.DatabaseConfigProvider
[info] 
[info] 1 error
[info]   at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1045)
[info]   at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
[info]   at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054)
[info]   at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:409)
[info]   at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:404)
[info]   at play.api.inject.ContextClassLoaderInjector$$anonfun$instanceOf$2.apply(Injector.scala:117)
[info]   at play.api.inject.ContextClassLoaderInjector.withContext(Injector.scala:126)
[info]   at play.api.inject.ContextClassLoaderInjector.instanceOf(Injector.scala:117)
[info]   at models.RackRepositorySpec.<init>(RackRepositorySpec.scala:26)
[info]   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

【问题讨论】:

你可以看看acolyte.eu.org 【参考方案1】:

我在 build.sbt 中使用 libraryDependencies += specs2 % Test 解决了问题。我希望这是 slick 的一个好习惯:

import org.specs2.mutable.Specification
import play.api.Application
import play.api.test.WithApplicationLoader

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await, Future
import scala.concurrent.duration.DurationInt

class RackRepositorySpec extends Specification 

  "RackRepository" should 
    "work as expected" in new WithApplicationLoader 
      val app2dao = Application.instanceCache[RackRepository]
      val rackRepository: RackRepository = app2dao(app)

      Await.result(rackRepository.delete("r-1"), 3 seconds)
      Await.result(rackRepository.delete("r-2"), 3 seconds)
      Await.result(rackRepository.delete("r-3"), 3 seconds)

      val testRacks = Set(
        RackRow("r-1", 0.2F, System.currentTimeMillis()),
        RackRow("r-2", 0.5F, System.currentTimeMillis()),
        RackRow("r-3", 0.8F, System.currentTimeMillis())
      )

      Await.result(Future.sequence(testRacks.map(rackRepository.insert)), 3 seconds)
      val storedRacks = Await.result(rackRepository.list(), 3 seconds)

      storedRacks.toSet must contain(testRacks)
    
  

【讨论】:

以上是关于尝试在 Scala 中为 Play Web 应用程序的 Slick 数据库创建单元测试的主要内容,如果未能解决你的问题,请参考以下文章

在 Play 2.1 和 Scala 中为文件上传编写测试用例

在 Play Framework 2.4 中为 Scala 实现 CORS

如何将 Play 2.2 Scala 应用程序创建为 SBT 子项目

Play Framework Routes 中的 Scala 反引号

Playframework2 中的 Scala 模板

升级 Play/Scala/SBT/jOOQ/HSQLDB 应用程序时出错