简体   繁体   中英

Trying to create Unit tests for Slick database for Play web application in Scala

I am struggling trying to configure unit tests for my Play web applications using Scala. I am using Play 2.6 and Scala 2.11.8. When I use the database configuration and execute sbt test I get the error No implementation for play.api.db.slick.DatabaseConfigProvider was bound on my console. So I am going to show how I set my web app and maybe someone could point what is wrong. Just for the sake, the web application is working well. It is just the unit test for the database that I cannot create.

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;"
  )
}

and I get this error when I execute 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)

I solved using the libraryDependencies += specs2 % Test in the build.sbt. I hope this is a good practice for 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)
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM