如何测试使用自定义 bodyparser 的播放框架控制器?

How to test a play framework controller that uses a custom bodyparser?

我正在尝试测试使用自定义 bodyparser 和 JSON 验证器的 play framework 2.5.10 控制器:

class MessagingController {
  def validateJson[A : Reads] = parse.json.validate(
    _.validate[A].asEither.left.map(e => BadRequest(JsError.toJson(e)))
  )
  def createMessageThread() = Action(validateJson[InboundMessageThread]) { request => 
    Ok("OK") }
  }

当我运行一个简单的测试用例时,我得到一个错误:

For request 'POST /api/v1/messageThreads' [Invalid Json: No content to map due to 
end-of-input at [Source: akka.util.ByteIterator$ByteArrayIterator$$anon@5693d1d2; line: 1, column: 0]]

测试是:

  val fakeRequest = FakeRequest()
      .withHeaders(HeaderNames.CONTENT_TYPE -> "application/json")
      .withBody(Json.parse(
        s"""
           |{
           |  "participants": [
           |   {"id": $currentUserId, "isAdmin": false}
           |  ],
           |  "isGroupThread": false
           |}
    """.stripMargin))

  val result =  messagingController.createMessageThread()(fakeRequest).run()
  status(result) mustBe OK

如果我将控制器的操作更改为仅 Action,然后验证控制器主体中的 JSON,它就可以正常工作。我不想这样做,因为我的很多 REST 控制器需要解析 JSON 并使用 validateJson[T] 减少样板。如果我使用 curl 提交相同的负载,该代码也有效。

如何测试这个控制器?

尝试一下,希望对您有所帮助

 val postRequest = FakeRequest(POST, "/route/to/hit").withJsonBody(Json.obj(
    "participants" -> Json.arr(Json.obj("id" -> "currentUserId", "isAdmin" -> false)),
    "isGroupThread" -> false
  ))

  val result =  await(messagingController.createMessageThread()(postRequest))

  status(result) must be equalTo (FORBIDDEN)

与其使用 JSON 主体解析器调用 Action,我建议使用 AnyContent 主体解析器通过 ActionBuilder 调用它,然后从主体内部调用 Json.validate - - 从那里,您可以获得堆栈跟踪并查看失败的内容:

class MessagingController {      
  def createMessageThread() = Action { request => 
    request.json.validate[MessageThread] {
      case JsError(e) =>           
         logger.error(s"Failure parsing because $e")
         BadRequest(JsError.toJson(e))
      case JsSuccess(e) =>      
         Ok("OK")
    }
  }
}

以下类型的请求有效:

val request = FakeRequest()
   .withHeaders(CONTENT_TYPE -> "application/json")
   .withBody(Json.fromJson[Place](body).get)