PlayFramework测试:在伪造请求错误中上传文件

时间:2015-04-17 14:06:08

标签: scala testing playframework

我想测试我的方法,这需要上传文件。它初始化如下:

val tempFile = TemporaryFile(new java.io.File("/home/ophelia/Desktop/students"))
val part = FilePart[TemporaryFile](
  key = "students", 
  filename = "students", 
  contentType = Some("text/plain"), 
  ref = tempFile)
val files = Seq[FilePart[TemporaryFile]](part)
val formData = MultipartFormData(
  dataParts = Map(), 
  files = Seq(part), 
  badParts = Seq(), 
  missingFileParts = Seq())

我把它传递给FakeRequest:

val result = route(
  FakeRequest(POST, "/api/courses/"+"4f3c4ec9-46bf-4a05-a0b2-886c2040f2f6"+"/import" )
    .withHeaders("Authorization" -> ("Session " + testSessionA.id.string))
    .withMultipartFormDataBody(formData)
)

但是当我运行测试时,我收到以下错误:

Cannot write an instance of play.api.mvc.AnyContentAsMultipartFormData to HTTP response. Try to define a Writeable[play.api.mvc.AnyContentAsMultipartFormData]

我做错了什么以及如何解决?我在互联网上查看,我没有找到任何有用的方法来理解和解决这个问题。

3 个答案:

答案 0 :(得分:5)

重要的是要记住http请求完全是文本。 route()使用隐式Writeable将提供的请求的正文类型转换为文本。如果没有正确的Writeable,则无法知道如何将MultipartFormData转变为请求正文。

似乎没有Writeable for MultipartFormData,但您可以提供自己的great Writeable。 jroper有a working Writeable for AnyContentAsMultipartFormData你可以用来参考。 (编辑:那个代码有问题,这里是{{3}})

获得Writeable后,您需要访问route()。请记住,您目前有一个FakeRequest[AnyContentAsMultipartFormData],而不是FakeRequest[MultipartFormData]。您可以先转换您的请求:

val request = FakeRequest(POST, 
    "/api/courses/"+"4f3c4ec9-46bf-4a05-a0b2-886c2040f2f6"+"/import" )
        .withHeaders("Authorization" -> ("Session "))
        .withMultipartFormDataBody(formData)
route(request.map(_.mdf).asInstanceOf[FakeRequest[MultipartFormData[TemporaryFile]]])

或将Writeable设为Writeable[AnyContentAsMultipartFormData]

答案 1 :(得分:3)

对于给定的route

Request[T]需要一个类型为Writeable[T]的隐式参数,它知道如何序列化请求体,因为它实际上会像实际的Web请求一样调用控制器操作将字节推到它上面。

问题是预定义没有Writeable[MultipartFormData](您可以看到play.api.test.Writeables中有哪些)。

这意味着您基本上有两个选择:

  1. 编写自己的Writeable,将MultipartFormData序列化为字节
  2. 跳过路由部分并直接调用操作,就像Play Framework Testing using MultipartFormData in a FakeRequest中接受的答案一样。这种测试操作的方式采用快捷方式,实际上并不是序列化和反序列化请求。
  3. 恕我直言,第一个选择是获得太大的痛苦,但是如果你沿着这条路前进,也许在你成功的时候有所贡献。

答案 2 :(得分:1)

可能的解决方案之一是使用wsUrl。例如

"File uploading action" should {

  "upload sent file and result in ID" in {
    val file = Paths.get(getClass.getResource("/1.txt").toURI)
    val action = wsUrl("/upload").post(Source.single(FilePart("file", "hello.txt", Option("text/plain"), FileIO.fromPath(file))))

    val res = Await.result(action, timeout)

    res.status mustBe OK
    res.body contains "123"
 }
}