如何使用 Json BodyParser 测试 Play REST API?

How do I test Play REST API with Json BodyParser?

我想为控制器编写一个简单的测试,它接受 json 主体。但是一旦我将 parse.json BodyParser 添加到 Action 中,我的测试就无法再编译了。 安装程序基本上是普通的 play-scala-seed 项目。

错误:

[error] ... could not find implicit value for parameter mat: akka.stream.Materializer
[error]       status(home) mustBe OK
[error]             ^

HomeController:

def index() = Action { implicit request =>
  Ok
}

def json() = Action(parse.json) { implicit request =>
  Ok
}

HomeControllerSpec:

class HomeControllerSpec extends PlaySpec with GuiceOneAppPerTest with Injecting {
  "HomeController POST" should {
    "answer Ok" in {
      val controller = new HomeController(stubControllerComponents())
      val home = controller.json().apply(FakeRequest(POST, "/"))
      status(home) mustBe OK
    }
  }

看来您需要在您的控制器中注入一个实体化器:

class Controller @Inject() (implicit val mat: Materializer) { ??? }

有关 stubControllerComponentsFakeRequest 调用的相关代码似乎存在两个问题。

Helpers.stubControllerComponents by default constructs ControllerComponents with NoMaterializer 使用时会抛出异常,因此我们需要提供一个实际的实体化器,如下所示:

       implicit val materializer = ActorMaterializer()(ActorSystem())

       Helpers.stubControllerComponents(
         playBodyParsers = Helpers.stubPlayBodyParsers(materializer)
       ) 

第二个问题是 FakeRequest,我们需要提供如下正文(否则会出现 4xx 错误):

FakeRequest(POST, "/json").withBody(Json.obj("name" -> "Jon Doe"))

考虑到以上我们可以写出完整的测试如下:

class HomeControllerSpec extends PlaySpec with GuiceOneAppPerTest {
  "HomeController POST" should {
    "answer Ok" in {
       implicit val materializer = ActorMaterializer()(ActorSystem())

       val controllerComponents = 
         Helpers.stubControllerComponents(
           playBodyParsers = Helpers.stubPlayBodyParsers(materializer)
         ) 

       val controller = new HomeController(controllerComponents)

       val fakeRequest = 
         FakeRequest(POST, "/json").withBody(Json.obj("name" -> "Jon Doe"))

       val home = call(controller.json(), fakeRequest)

       status(home) mustBe OK
    }
  }
}