Тестирование контроллера Play Framework, который передает ответы - PullRequest
2 голосов
/ 21 января 2020

У меня есть контроллер, который отправляет ответ по частям:

def streamDatase2t(query:String): Action[AnyContent] = Action.async {
    req =>
        serivce.getIterator(query).map(res => {
            Ok.chunked(Source.apply(res))
        })
  }

Когда я пытаюсь проверить возвращенное содержимое в контроллере, spe c я получаю исключение:

  "return 200 response with the content of the iterator" in {
      when(serivce.getIterator
      (Matchers.any[Request.DatasetLoad],
        Matchers.any[ResponseFormat], Matchers.any[Int]))
        .thenReturn(Future.successful(new FakeIterable(List("One", "Two", "Three").iterator)))

      val fakeRequest = FakeRequest.apply("GET", s"/data")

      val result = Helpers.route(fakeApp, fakeRequest).get
      checkStatus(result, OK)
      contentAsString(result) // <-- exception here ! 
    }

Исключение:

NoMaterializer cannot materialize
java.lang.UnsupportedOperationException: NoMaterializer cannot materialize
    at play.api.test.NoMaterializer$.materialize(Helpers.scala:732)
    at akka.stream.scaladsl.RunnableGraph.run(Flow.scala:629)
    at akka.stream.scaladsl.Source.runWith(Source.scala:106)
    at akka.stream.scaladsl.Source.runFold(Source.scala:117)
    at play.api.http.HttpEntity.consumeData(HttpEntity.scala:49)
    at play.api.http.HttpEntity.consumeData$(HttpEntity.scala:48)
    at play.api.http.HttpEntity$Chunked.consumeData(HttpEntity.scala:117)
    at play.api.test.ResultExtractors.contentAsBytes(Helpers.scala:381)
    at play.api.test.ResultExtractors.contentAsBytes$(Helpers.scala:379)
    at play.api.test.Helpers$.contentAsBytes(Helpers.scala:676)

Ответы [ 2 ]

2 голосов
/ 21 января 2020

В качестве состояния исключения NoMaterializer cannot materialize может потребоваться добавить Materializer:

implicit lazy val mat = ActorMaterializer()
implicit lazy val ec = instanceOf[ExecutionContext]
1 голос
/ 21 января 2020

contentAsString имеет NoMaterializer в качестве аргумента по умолчанию

def contentAsString(of: Future[Result])(implicit timeout: Timeout, mat: Materializer = NoMaterializer): String

NoMaterializer просто выбрасывает UnsupportedOperationException для всего, поэтому попробуйте предоставить ваш собственный

implicit val actorSystem = ActorSystem("test")
implicit val materializer = ActorMaterializer()

play- scala -streaming-example демонстрирует, как можно написать тест для контроллера потоковой передачи.


Обращаясь к комментарию, рассмотрим следующие два маршрута, которые иллюстрируют разницу между строгим и нестрогим (чанкованным, потоковым) телом

def nonStrictBody = Action {
  val source = Source.apply(List("woo", "h", "oo"))
  Ok.chunked(source)
}

def strictBody = Action {
  Ok("woohoo")
}

При вызове contentAsString на строгом теле , то материализатор не будет использоваться, следовательно, NoMaterializer является достаточным

В 99% случаев при выполнении тестов с телом результата на самом деле вам не требуется материализатор, поскольку это строгий корпус. Таким образом, вместо того, чтобы всегда требовать неявного материализатора, мы используем его, если он есть, в противном случае у нас есть стандартный, который просто генерирует исключение, если используется.

Однако при вызове contentAsString для Тело chunked или с потоковым , как это имеет место в маршруте nonStrictBody, тогда мы должны предоставить правильное Materializer.

...