【问题标题】:How to test file upload in Play 2.2.2?如何在 Play 2.2.2 中测试文件上传?
【发布时间】:2014-07-28 00:32:57
【问题描述】:

我正在使用 Play 2.2.2,但未能成功尝试向我的文件上传功能添加测试。我知道有很多关于这个的问题,我检查了很多,但要么它们不起作用,要么 API 已被弃用并且不起作用,或者它因一些虚假错误而失败。

这是来自浏览器的有效请求的样子(使用 Firefox 的 WebDeveloper 插件):

-----------------------------479326525221683770414613115
Content-Disposition: form-data; name="files[]"; filename="upload_aum_sample.csv"
Content-Type: text/csv

AccountName,AuM,Name
IX_CH1,10,A
IX_CH2,20,B
IX_CH3,30,C
IX_CH4,40,D
IX_CH5,50,E
IX_CH6,60,F
IX_CH7,70,G
IX_CH8,80,H

-----------------------------479326525221683770414613115--

这是我迄今为止尝试过的,但没有成功:


编译时带有警告,即 routeAndCall 已弃用:

"upload file correctly" in new WithApplication {
  val fileName = "upload_aum_sample.csv"
  val file = getClass().getResource(fileName).getFile()
  val data = MultipartFormData(Map(), List(FilePart("files[]", fileName, Some("text/csv"), file)), List(), List())
  val result = routeAndCall(FakeRequest(POST, "/aum/upload/do", FakeHeaders(), data).withSession("username" -> "Test")).get    
  status(result) must equalTo(OK)
  contentType(result) must beSome.which(_ == "application/json")
}

并导致异常:

[info] ! upload file correctly
[error]   MatchError: <function1> (of class play.core.Router$Routes$$anon$4) (Helpers.scala:187)
[error] play.api.test.RouteInvokers$$anonfun$routeAndCall$1.apply(Helpers.scala:187)
[error] play.api.test.RouteInvokers$$anonfun$routeAndCall$1.apply(Helpers.scala:187)
[error] play.api.test.RouteInvokers$class.routeAndCall(Helpers.scala:187)
[error] AumUploadPageSpec.routeAndCall(AumUploadPageSpec.scala:30)
[error] play.api.test.RouteInvokers$class.routeAndCall(Helpers.scala:178)
[error] AumUploadPageSpec.routeAndCall(AumUploadPageSpec.scala:30)
[error] AumUploadPageSpec$$anonfun$12$$anon$3$delayedInit$body.apply(AumUploadPageSpec.scala:73)
[error] play.api.test.WithApplication$$anonfun$around$1.apply(Specs.scala:20)
[error] play.api.test.WithApplication$$anonfun$around$1.apply(Specs.scala:20)
[error] play.api.test.PlayRunners$class.running(Helpers.scala:45)
[error] play.api.test.Helpers$.running(Helpers.scala:364)
[error] play.api.test.WithApplication.around(Specs.scala:20)
[error] play.api.test.WithApplication.delayedInit(Specs.scala:17)
[error] AumUploadPageSpec$$anonfun$12$$anon$3.<init>(AumUploadPageSpec.scala:48)
[error] AumUploadPageSpec$$anonfun$12.apply(AumUploadPageSpec.scala:48)
[error] AumUploadPageSpec$$anonfun$12.apply(AumUploadPageSpec.scala:48)

编译正常,没有警告

"upload file correctly" in new WithApplication {
  val fileName = "upload_aum_sample.csv"
  val file = getClass().getResource(fileName).getFile()
  val data = MultipartFormData(Map(), List(FilePart("files[]", fileName, Some("text/csv"), file)), List(), List())
  val result = controllers.Application.uploadDo("aum")(FakeRequest(POST, "/aum/upload/do", FakeHeaders(), data).withSession("username" -> "Test")).run
  status(result) must equalTo(OK) // <<<<<<< test fails here 
  contentType(result) must beSome.which(_ == "application/json")
}

但由于服务器响应 400 而不是 200 即不正常,测试失败

[info] x upload file correctly
[error]  '400' is not equal to '200' (AumUploadPageSpec.scala:53)

更新 1: 如果嵌入文件内容而不是文件,我仍然会收到相同的错误,即 改变

val file = getClass().getResource(fileName).getFile()

val file = scala.io.Source.fromFile(getClass().getResource(fileName).getFile()).map(_.toByte).toArray

更新 2:这些分别是路由和服务器端代码:

# Generic controllers
POST  /:context/upload/do  controllers.Application.uploadDo(context: String)

//------------------------------------------------------------------------
/**
 * Action that uploads a file for a given context
 * @param context the input context
 */
def uploadDo(context: String) = Action(parse.multipartFormData) { implicit request ⇒
 request.body.file("files[]").map { file ⇒
   val filename = file.filename
   val contentType = file.contentType
 }
 Ok(Json.parse(
   """{"files": [
    {
      "name": "picture1.jpg",
      "size": 902604,
      "error": "Filetype not allowed"
    },
    {
      "name": "picture2.jpg",
      "size": 841946,
      "error": "Filetype not allowed"
    }
]}"""))
}

【问题讨论】:

  • Application.uploadDo 长什么样子?
  • 不看函数就很难调试它。
  • 我知道,谢谢您的关注 :) 我在办公室拿到了代码,现在在家里……直到星期二才能更新。但我认为它没有帮助,由于这些错误,它甚至没有执行函数,错误发生在 Play 框架级别,然后再进入任何应用程序服务器端代码。
  • 如果返回带有状态的结果,则应用程序中发生了一些事情
  • 我卡住了一个调试器,但动作函数没有任何反应,它没有到达那里,但为了完整起见,我明天会发布代码。

标签: scala playframework playframework-2.2


【解决方案1】:

this question 的最佳答案(令人恼火的是不被接受)解决了我的问题。为了完整起见,我将其包含在此处。

trait FakeMultipartUpload {
  case class WrappedFakeRequest[A](fr: FakeRequest[A]) {
    def withMultipart(parts: (String, ContentBody)*) = {
      // create a multipart form
      val entity = new MultipartEntity()
      parts.foreach { part =>
        entity.addPart(part._1, part._2)
      }

      // serialize the form
      val outputStream = new ByteArrayOutputStream
      entity.writeTo(outputStream)
      val bytes = outputStream.toByteArray

      // inject the form into our request
      val headerContentType = entity.getContentType.getValue
      fr.withBody(bytes).withHeaders(CONTENT_TYPE -> headerContentType)
    }

    def withFileUpload(fileParam: String, file: File, contentType: String) = {
      withMultipart(fileParam -> new FileBody(file, contentType))
    }
  }

  implicit def toWrappedFakeRequest[A](fr: FakeRequest[A]) = WrappedFakeRequest(fr)

  // override Play's equivalent Writeable so that the content-type header from the FakeRequest is used instead of application/octet-stream  
  implicit val wBytes: Writeable[Array[Byte]] = Writeable(identity, None)
}

@RunWith(classOf[JUnitRunner])
class AumUploadPageSpec extends PlaySpecification with FakeMultipartUpload {
  //------------------------------------------------------------------------
  "upload file correctly" in new WithApplication {
    val fileName = "idxsrs_aum_2014-06-04.csv"
    val uploadFile = new File(getClass().getResource(fileName).getPath())
    val request = FakeRequest(POST, "/aum/upload/do").withFileUpload("files[]", uploadFile, "text/csv")
    val response = route(request).get
    status(response) must equalTo(OK)
    contentType(response) must beSome.which(_ == "application/json")
  }
}

【讨论】:

    猜你喜欢
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 2019-10-27
    • 1970-01-01
    • 2013-02-14
    • 2021-01-27
    • 2023-03-18
    相关资源
    最近更新 更多