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

Is there a bug in Play2 testing with FakeRequests and chunked responses (Enumerator)?

我 运行 在测试 returns 使用枚举器的分块响应的 Action 时遇到 Play 2.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 和 Enumerators 的问题?在操作中连接枚举器的更复杂情况下,枚举器生成的内容之间将混合字符。

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

我一直在使用以下代码来解决 2.3.x 上的问题(感谢 marcuslinke 的 post 来自这个 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)
}

我在这样的测试 (specs2) 中使用:

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

作为参考,这里是合并到 master 中的 pull request