【问题标题】:Testing Play framework controller that streams responses测试流响应的 Play 框架控制器
【发布时间】:2020-05-07 10:33:58
【问题描述】:

我有一个发送分块响应的控制器:

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

当我尝试检查控制器规范中返回的内容时,我得到一个异常:

  "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)

【问题讨论】:

  • 考虑根据meta.stackexchange.com/questions/19190/…从标题中删除标签
  • @MarioGalic 这实际上有点奇怪,但在 Google 搜索引擎中,人们往往会点击他们使用的关键字最多的标题。保持原样会有问题吗?

标签: scala playframework stream


【解决方案1】:

由于异常状态NoMaterializer cannot materialize,您可能需要添加Materializer

implicit lazy val mat = ActorMaterializer()
implicit lazy val ec = instanceOf[ExecutionContext]

【讨论】:

    【解决方案2】:

    contentAsString 具有 NoMaterializer 作为默认参数

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

    NoMaterializer 只是抛出 UnsupportedOperationException 来处理所有事情,所以请尝试提供 your own

    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 时,将不会使用物化器,因此NoMaterializersufficient

    在 99% 的情况下,在针对结果主体运行测试时,您不会 实际上需要一个物化器,因为它是一个 strict 体。所以,而不是 总是需要一个隐式实现器,如果提供,我们使用一个, 否则我们有一个默认的,如果 用过。

    但是,当在 chunkedstreamed 主体上调用 contentAsString 时,就像在 nonStrictBody 路由中一样,那么我们需要提供正确的 Materializer

    【讨论】:

    • 但是为什么当我将服务更改为返回字符串而不是 Iterator[String] 时,它不需要物化器?
    猜你喜欢
    • 2016-11-14
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多