Scala 如何在控制器中执行单元测试?

Scala 如何在控制器中执行单元测试?,scala,specs2,playframework-2.4,Scala,Specs2,Playframework 2.4,比如说,我有如下控制器: class JenisKejahatanControl @Inject()(service: JenisKejahatanService, val messagesApi: MessagesApi) extends Controller with I18nSupport { def add = Action.async { implicit request => lazy val incoming = JenisKejahatan.formJenis

比如说,我有如下控制器:

class JenisKejahatanControl @Inject()(service: JenisKejahatanService, val messagesApi: MessagesApi) extends Controller with I18nSupport {

  def add = Action.async { implicit request =>
    lazy val incoming = JenisKejahatan.formJenisK.bindFromRequest()

    incoming.fold( error => {
      lazy val response = ErrorResponse(BAD_REQUEST, messagesApi("request.error"))
      Future.successful(BadRequest(Json.toJson(response)))
    }, { newJenisK =>
      lazy val future = service.addJenisK(newJenisK)
      future.flatMap {
        case Some(jenis) => Future.successful(Created(Json.toJson(SuccessResponse(jenis))))
        case None => Future.successful(BadRequest(Json.toJson(ErrorResponse(NOT_FOUND, messagesApi("add.jenis.kejahatan.fail")))))
      }
    })
  }
}

我想用specs2测试我的def add,怎么做?

因为你的控制器已经注入了组件,我认为你缺少的一点是如何在满足各种依赖关系的情况下在你的spec中获得它的实例。为此,您可以使用获取播放应用程序实例,然后使用其
injector
获取控制器实例,而无需手动构建它(更多依赖项注入文档,特别是关于使用Guice进行测试的文档)

如果您可以手动构造控制器(如示例中所示),这很好,而且会使事情变得更简单,但是控制器往往具有非琐碎的依赖关系,您很可能希望使用
GuiceApplicationBuilder
上的
overrides
方法模拟这些依赖关系

构造了控制器的实例后,将模拟(伪)请求“应用”到动作方法并确定它们给出了您期望的状态和主体,就非常简单了。下面是一个例子:

import controllers.{SuccessResponse, JenisKejahatanControl}
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.inject.bind
import play.api.mvc.Result
import play.api.test.{FakeRequest, PlaySpecification}

import scala.concurrent.Future

class JenisKejahatanControlSpec extends PlaySpecification {

  "JenisKejahatanControl#add" should {
    "be valid" in {

      // Build an instance of a Play application using the
      // default environment and configuration, and use it
      // to obtain an instance of your controller with the
      // various components injected.
      val jenisController = new GuiceApplicationBuilder()
        .overrides(  // Mock the data service
          bind[JenisKejahatanService]
           .toInstance(new MockJenisKejahatanService))
        .build()
        .injector
        .instanceOf[JenisKejahatanControl]

      // Create a "fake" request instance with the appropriate body data
      val request = FakeRequest().withFormUrlEncodedBody("name" -> "test")

      // Apply the request to your action to obtain a response
      val eventualResult: Future[Result] = jenisController.add.apply(request)

      // Check the status of the response
      status(eventualResult) must_== CREATED

      // Ensure the content of the response is as-expected
      contentAsJson(eventualResult).validate[SuccessResponse].asOpt must beSome.which { r =>
        r.jenis.name must_== "test"
      }
    }
  }
}

我已经读过了,但我仍然不明白如何将其应用于我的控制器。您想测试什么?这种方法的逻辑是什么?路线?你能用语言描述一下你想测试什么吗?(这里可以写很多测试)对不起,我是单元测试的初学者。我想测试add方法的路由,例如:当我运行route/api/add/jenis时,它会将数据jenis kejahatan添加到数据库中,而不必使用postman?抱歉,如果我的英语这么差哇,谢谢,但是我仍然不知道如何使用组件JenisKejahatanService和MessageApi的GuiceApplicationBuilder?@kurokoA2,因为JenisKejahatanService和MessagesApi都是控制器的注入依赖项,GuiceApplicationBuilder应该负责将它们与我发布的代码连接起来。如果不了解更多关于您的应用程序的信息,我无法深入了解更多细节,而您在问题中已经发布了(这实际上是一个不同的问题。)请务必阅读文档。@kurokoA2我已经用模拟测试覆盖了数据服务,扩展了示例。您不必担心消息SAPI-应用程序生成器将使用默认的消息。当我尝试生成生成实例时,出现了找不到错误类型MockJenisKejahatanService,如何定义MockJenisKejahatanService?