在 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 以防我遗漏了什么。
我有以下使用 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 以防我遗漏了什么。