在FakeRequest中使用MultipartFormData进行框架测试

时间:2013-10-29 12:52:45

标签: scala testing playframework multipartform-data specs2

我目前正在为Play Framework 2.2.x应用程序编写一些Specs2测试,该应用程序接受MultipartFormData提交作为其功能的一部分。

我已使用以下格式成功地使用text和JSON主体编写了其他测试:

"respond to POST JSON with description field present" in {
  running(FakeApplication()) {
    val response = route(FakeRequest(POST, "/submission.json").withJsonBody(toJson(Map("content" -> toJson("test-content"), "description" -> toJson("test-description"))))).get
    status(response) must equalTo(OK)
    contentType(response) must beSome.which(_ == "application/json")
    contentAsString(response) must contain(""""description":"test-description"""")
    contentAsString(response) must contain(""""content":"test-content"""")
  }
}

但是,当我使用.withMultipartFormData方法时,我会收到以下错误:

Cannot write an instance of play.api.mvc.AnyContentAsMultipartFormData to HTTP response. Try to define a Writeable[play.api.mvc.AnyContentAsMultipartFormData]
val response = route(FakeRequest(PUT,"/submission.json/1/files").withMultipartFormDataBody(data)).get
                    ^

我尝试调试的MultipartFormData测试的形式如下:

"respond to file PUT form with details not specififed" in {
  running(FakeApplication()) {
     val basePath:String = Play.application.path.getCanonicalPath();
     val data:MultipartFormData[TemporaryFile] = MultipartFormData(Map[String,Seq[String]](),
                                    List(
                                        FilePart("file_upload","",Some("Content-Type: multipart/form-data"),TemporaryFile(new java.io.File(basePath + "/test-data/testUpload.jpg")))
                                    ), 
                                    List(), 
                                    List())


     val response = route(FakeRequest(PUT,"/submission.json/1/files").withMultipartFormDataBody(data)).get
     status(response) must equalTo(CREATED)
 }
}

查看相关版本的FakeRequest类的Play Framework文档,我看不到太多帮助我追查问题:play.api.test.FakeRequest

就其他有关此事的文件而言,Play Framework网站和谷歌似乎相当缺乏。

我尝试了以下替代方法来尝试测试我的MultipartFormData代码:

但是,我对这些方法都没有任何成功。

3 个答案:

答案 0 :(得分:7)

当测试并行运行时,我不是在FakeApplication中进行测试,而且速度很慢(根据我的经验)可能容易出错,我已经单元测试我的Multipart表单像这样上传处理程序:

  1. 从控制器中的实际上传处理中拆分播放接线; e.g:

    def handleUpload = Action(parse.multipartFormData) { implicit request =>
      doUpload(request)
    }
    
    def doUpload(request:Request[MultipartFormData[TemporaryFile]]) = {
      ...
    }
    

    (其中handleUpload是routes文件中处理POST的方法)

  2. 现在您已经有了一个更容易获得的端点,您可以模拟您的服务层以适当地响应好/坏请求,并将模拟服务注入您的控制器在测试中(我不会在这里显示,有一百万种不同的方法)

  3. 现在模拟了一个多部分请求,它将以doUpload方式到达:

    val request= mock[Request[MultipartFormData[TemporaryFile]]]
    val tempFile = TemporaryFile("do_upload","spec")
    val fileName = "testFile.txt"
    val part = FilePart("key: String", fileName, None, tempFile)
    val files = Seq[FilePart[TemporaryFile]](part)
    val multipartBody = MultipartFormData(Map[String, Seq[String]](), files, Seq[BadPart](), Seq[MissingFilePart]())
    request.body returns multipartBody 
    
  4. 最后,您可以调用doUpload方法和验证功能

    val result = controller.doUpload(request)
    status(result) must beEqualTo(201)
    
  5. 通过这样的测试,您可以快速轻松地测试Controller中的所有错误处理路径(这可能是您最终想要做的事情),而无需启动整个过程的开销应用

答案 1 :(得分:2)

(我在另一个帖子中回答:PlayFramework Testing: Uploading File in Fake Request Errors

简而言之,您需要一个可写的[AnyContentAsMultipartFormData],它将MultipartFormData[TemporaryFile]变为Array[Byte],您可以从此处获取它:http://tech.fongmun.com/post/125479939452/test-multipartformdata-in-play

答案 2 :(得分:2)

在Play 2.5.x中,可以轻松测试文件上传

  val file = new java.io.File("the.file")
  val part = FilePart[File](key = "thekey", filename = "the.file", contentType = None, ref = file)
  val request =  FakeRequest().withBody(
    MultipartFormData[File](dataParts = Map.empty, files = Seq(part), badParts = Nil)
  )
  val response = controller.create().apply(request)
  status(response) must beEqualTo(201)