代码之家  ›  专栏  ›  技术社区  ›  Stefan K.

使用FakeRequest和分块响应(Enumerator)进行Play2测试时是否存在错误?

  •  2
  • Stefan K.  · 技术社区  · 11 年前

    在使用枚举器测试返回分块响应的Action时,我遇到了Play2.3.7的问题:

    def text = Action {
        Ok.chunked(Enumerator("abc"))
    }
    

    使用 curl http://localhost:9000/text 我得到了预期的结果: abc 但进行以下测试:

    class ApplicationSpec extends Specification {
        "Application" should {
            "stream text" in new WithApplication{
                val request = route(FakeRequest(GET, "/text")).get
                contentAsString(request) mustEqual "abc"
            }
        }
    }
    

    失败,并出现比较错误:

    [info] Application should
    [info] x stream text
    [error]    '3
    [error]    abc
    [error]    0
    [error]    
    [error]    ' is not equal to 'abc' (ApplicationSpec.scala:31)
    

    这些额外的字符来自哪里?我怀疑这可能是FakeRequest和Enumerator的问题?在一个更复杂的情况下,在操作中使用串联的枚举器,枚举器生成的内容之间会混合字符。

    1 回复  |  直到 11 年前
        1
  •  4
  •   Michael Zajac    11 年前

    这是一个已知的问题,已在即将推出的Play2.4中修复,但2.3.x中不可用。额外的字符是从分块编码中引入的。它们以十六进制表示块长度,位于每个HTTP响应主体的开头。旧的游戏测试助手只是将它们连接在一起,而不是将它们剔除。

    目前,我一直在使用以下代码来解决2.3.x上的问题(感谢marcuslinke的帖子 github issue ):

    import scala.concurrent._
    import scala.concurrent.duration._
    import play.api.mvc._
    import play.api.libs.iteratee._
    import akka.util.Timeout
    
    def contentAsBytes(of: Future[Result])(implicit timeout: Timeout): Array[Byte] = {
        val result = Await.result(of, timeout.duration)
        val eBytes = result.header.headers.get(TRANSFER_ENCODING) match {
            case Some("chunked") => result.body &> Results.dechunk
            case _ => result.body
        }
        Await.result(eBytes |>>> Iteratee.consume[Array[Byte]](), timeout.duration)
    }
    

    我在如下测试(第2条)中使用:

    new String(contentAsBytes(result)) must equalTo("expected value")
    

    作为参考,以下是 pull request 已合并到master中。