2016-12-25 62 views
9

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

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

+0

挣扎与完全相同的问题=> http://stackoverflow.com/questions/41369252/scala-play-and-scalatest-directory-structure-mismatch –

+0

'DatabaseConfigProvider.get [JdbcProfile](“mydb”)'? –

+0

@ insan -e这会引发错误:'type mismatch;找到:slick.backend.DatabaseConfig [slick.driver.JdbcProfile]必需:play.api.db.slick.DatabaseConfigProvider' – ps0604

回答

4

恕我直言,最好不要干扰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的情况下,我错过了什么。

+0

在使用OneAppPerSuite的代码示例中,可以使用一个应用程序运行多个测试套件吗? –

+0

我还没有尝试过它,但它应该工作...你将不得不手动分组这些套件(并把'@ DoNotDiscover'),看看这个例子:http://stackoverflow.com/questions/15423337/做出头,后众人面前 - 或 - - scalatest检验 –

3

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

看看你的代码示例,我假设后者。

如果你真的想这样做,你开始了,最简单的解决办法是这样的:

// 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] 

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

完整代码

测试/资源/ 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拉到所有依赖项注入)。

+0

你的第一个解决方案不起作用,它抛出'type mismatch;找到:slick.backend.DatabaseConfig [slick.driver.JdbcProfile] required:play.api.db.slick.DatabaseConfigProvider' – ps0604

+0

关于你的第二个解决方案,我可以在'application.conf'中配置db,但是我怎么注入数据库配置在道?请记住,我正在使用ScalaTest – ps0604

+0

现在你已经有了完整的答案,你是对的,那是错误的,现在它会像魅力一样工作。 –