是否可以在游戏功能测试中模拟数据库连接?如何模拟?

Is it possible to mock DB connection in play functional testing and how?

我的一些控制器依赖于数据库连接,结构如下:

def getAll(revId: Muid) = Action { implicit request =>
        DB.withConnection { implicit connection =>
...

我正在尝试为它创建一个单元测试,其中包含所有模拟的依赖项,包括连接。现在,通过 Guice 可以轻松地注入依赖项。但是,我正在努力寻找一种方法来模拟隐式连接。而且,最终,测试正在尝试连接到我在测试中的默认数据库。

在这种情况下,甚至可以模拟隐式吗?如何模拟?

更新

所以,在玩了一会儿这个东西之后,我得到了以下信息: 我的 class 正在测试中:

class ChecklistCreationScheduler @Inject()(jobScheduler: JobScheduler,
                                           dBApi: DBApi,
                                           futureChecklistRepository: FutureChecklistRepository) extends ClassLogger{
def scheduleSingleFutureChecklistJob(futureChecklistId: Muid): Unit = {
    logger.info(s"Preparing to schedule one time future checklist job for future checklist id '${futureChecklistId.uuid}'")
    val db = dBApi.database("default")
    logger.info("Database" + db)
    db.withConnection { implicit connection =>
      logger.info("Connection" + connection)
      ...
    }
}
}

测试:

"ChecklistCreationScheduler#scheduleSingleFutureChecklistJob" should {
      "schedule a single job through a scheduler" in {
        val futureChecklistId = Muid.random()

        val jobScheduler = mock[JobScheduler]

        val connection = mock[Connection]
        val DB = mock[Database]
        DB.getConnection returns connection

        val dbApi = mock[DBApi]
        when(dbApi.database("default")).thenReturn(DB)

        val futureChecklistRepository = mock[FutureChecklistRepository]
        doReturn(Option.empty).when(futureChecklistRepository).getById(futureChecklistId)(connection)

        val chCreationScheduler = new ChecklistCreationScheduler(jobScheduler, dbApi, futureChecklistRepository)

        chCreationScheduler.scheduleSingleFutureChecklistJob(futureChecklistId) must throwA[UnexpectedException]
      }
    }

当我执行测试时,似乎执行甚至没有进入 withConnection 的块。 (我永远不会进入这一行:logger.info("Connection" + connection))。

有什么想法吗?

以下是如何使用 Dependency Injection 轻松模拟数据库调用:

考虑到这是您的控制器:

package controllers

import javax.inject.Inject

import play.api._
import play.api.db.Database
import play.api.mvc._

class Application @Inject() (database: Database) extends Controller {

  def index = Action { implicit request =>
    database.withConnection { implicit  connection =>
      ???
    }
    Ok(views.html.index("Your new application is ready."))
  }
}

你可以写一个Specification like this:

import java.sql.Connection

import controllers.Application
import org.specs2.mutable._
import org.specs2.runner._
import org.junit.runner._
import org.specs2.mock._
import play.api.db.Database
import play.api.mvc.RequestHeader

@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification with Mockito {

  "Application" should {

    "index page" in {
      val connection = mock[Connection]
      val database = mock[Database]
      database.getConnection returns connection

      val controller = new Application(database)

      // You will also need to mock the request
      // so that you can add the expected behavior 
      val request = mock[RequestHeader]
      val result = controller.index(request)

      // do some assert about your result
      result must not beNull
    }
  }
}

当然,处理您的(整个)用例可能需要一些其他模拟。