2016-12-25 63 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

現在你已經有了完整的答案,你是對的,那是錯誤的,現在它會像魅力一樣工作。 –