在 ScalaTest 中注入 PlaySlick 数据库连接

Injecting PlaySlick database connection in ScalaTest

我有以下使用 PlaySlick 连接到数据库的 DAO。 class 有一个方法 read,我需要使用 ScalaTest 对其进行测试。我的问题是我不知道如何模拟 DatabaseConfigProvider 以将其注入 UsersDAO class 并测试 read 方法。这是要测试的class:

class UsersDAO @Inject()(@NamedDatabase("mydb") 
          protected val dbConfigProvider: DatabaseConfigProvider)
          extends with HasDatabaseConfigProvider[JdbcProfile] {

   import driver.api._

   val db1 = dbConfigProvider.get[JdbcProfile].db

   def read (sk: Int) = {
      val users = TableQuery[UserDB]
      val action = users.filter(_.sk === sk).result
      val future = db1.run(action.asTry)
      future.map{
        case Success(s) => 
          if (s.length>0)
            Some(s(0))
          else
            None
        case Failure(e) => throw new Exception ("Failure: " + e.getMessage)
      }
   }

}

这是我编写测试的尝试:

class UserDAOTest extends PlaySpec with OneAppPerSuite  {

  implicit override lazy val app = new GuiceApplicationBuilder().
  configure(
            Configuration.from(
                Map(
                    "slick.dbs.mydb.driver" -> "slick.driver.MySQLDriver$",
                    "slick.dbs.mydb.db.driver" -> "com.mysql.jdbc.Driver",
                    "slick.dbs.mydb.db.url" -> "jdbc:mysql://localhost:3306/control",
                    "slick.dbs.mydb.db.user" -> "root",
                    "slick.dbs.mydb.db.password" -> "xxxxx"
                )
            )
        ).build

  val dbConfigProvider = app.injector.instanceOf[DatabaseConfigProvider]

  "Example " should {
    "be valid" in {

      val controller = new UsersDAO(dbConfigProvider)
      val result = controller.read(1)
      println(result) 
    }
  }

当我 运行 测试失败并显示以下错误消息时:

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

1) No implementation for play.api.db.slick.DatabaseConfigProvider was bound. while locating play.api.db.slick.DatabaseConfigProvider

我不确定你是想从你的测试中完全模拟数据库,还是只是使用不同的数据库配置。

查看您的代码示例,我假设是后者。

如果您真的想一开始就这样做,最简单的解决方案是:

// instead of your line below
//  val dbConfigProvider = app.injector.instanceOf[DatabaseConfigProvider]
// use this:
   val userDao = app.injector.instanceOf[UsersDao]

以上将注入您的 DAO 并隐式处理您的 DatabaseConfigProvider

但我不明白一件事 - 你为什么不在你的测试资源中创建另一个配置 (application.conf),内容如下:

slick.dbs.mydb.driver="slick.driver.MySQLDriver$"
slick.dbs.mydb.db.driver="com.mysql.jdbc.Driver"
slick.dbs.mydb.db.url = "jdbc:mysql://localhost:3306/control"
slick.dbs.mydb.db.user=root
slick.dbs.mydb.db.password="xxxxx"

完成此操作后,只需将您的 app 创建更改为:

implicit override lazy val app = new GuiceApplicationBuilder().build

并且通常像这样注入 UsersDao(与上面的方法相同):

val usersDao = app.injector.instanceOf[UsersDao]

?

(我在上面假设你只是在测试和应用程序中有不同的数据库配置)。

完整代码

test/resource/application.conf

slick.dbs.mydb.driver="slick.driver.MySQLDriver$"
slick.dbs.mydb.db.driver="com.mysql.jdbc.Driver"
slick.dbs.mydb.db.url = "jdbc:mysql://localhost:3306/control"
slick.dbs.mydb.db.user=root
slick.dbs.mydb.db.password="xxxxx"

UserDaoTest.scala

import scala.concurrent.Await
import scala.concurrent.duration.DurationInt
//... other imports

class UserDAOTest extends PlaySpec with OneAppPerSuite  {

  implicit override lazy val app = new GuiceApplicationBuilder().build

  val userDao = app.injector.instanceOf[UsersDao]

  "Example " should {
    "be valid" in {
      val result = userDao.read(1)
      println(Await.result(result), 1.second) 

      // would be better to use whenReady from org.scalatest.concurrent.Futures
      // but it's not really related to this question that much
    }
  }
}

总结

我认为这里的结论是避免手动构造对象(就像在第一种方法中一样——使用带参数的构造函数创建 UsersDao)。如果您不需要这样做(有时您会这样做 - 例如当您想要更改某些参数时),大多数时候将整个对象构造委托给 DI 会更容易(例如 - 只需拉 UsersDao已注入所有依赖项)。

恕我直言,最好不要干扰Play 的注入的东西,而只是使用它。这应该有效:

class UserDAOTest extends PlaySpec with OneAppPerSuite with ScalaFutures {

  implicit override lazy val app = new GuiceApplicationBuilder().
    configure(
      "slick.dbs.mydb.driver" -> "slick.driver.MySQLDriver$",
      "slick.dbs.mydb.db.driver" -> "com.mysql.jdbc.Driver",
      "slick.dbs.mydb.db.url" -> "jdbc:mysql://localhost:3306/control",
      "slick.dbs.mydb.db.user" -> "root",
      "slick.dbs.mydb.db.password" -> "xxxxx").build

  def userDAO(implicit app: Application): UserDAO = Application.instanceCache[UserDAO].apply(app)

  "UserDAO" should {
    "do whatever" in {
      whenReady(userDAO.read(1)) { res =>
        println(res)
      }
    }
  }

}

我已经更新了我的 repo 以防我遗漏了什么。