Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a test case for file uploads in Play 2.1 and Scala

I found the following question/answer:

Test MultipartFormData in Play 2.0 FakeRequest

But it seems things have changed in Play 2.1. I've tried adapting the example like so:

"Application" should {

"Upload Photo" in {
  running(FakeApplication()) {
    val data = new MultipartFormData(Map(), List(
        FilePart("qqfile", "message", Some("Content-Type: multipart/form-data"), 
            TemporaryFile(getClass().getResource("/test/photos/DSC03024.JPG").getFile()))
        ), List())
    val Some(result) = routeAndCall(FakeRequest(POST, "/admin/photo/upload", FakeHeaders(), data)) 
    status(result) must equalTo(CREATED)
    headers(result) must contain(LOCATION)
    contentType(result) must beSome("application/json")  

However whenever I attempt to run the request, I get a null-pointer exception:

[error] ! Upload Photo
[error]     NullPointerException: null (PhotoManagementSpec.scala:25)
[error] test.PhotoManagementSpec$$anonfun$1$$anonfun$apply$3$$anonfun$apply$4.apply(PhotoManagementSpec.scala:28)
[error] test.PhotoManagementSpec$$anonfun$1$$anonfun$apply$3$$anonfun$apply$4.apply(PhotoManagementSpec.scala:25)
[error] play.api.test.Helpers$.running(Helpers.scala:40)
[error] test.PhotoManagementSpec$$anonfun$1$$anonfun$apply$3.apply(PhotoManagementSpec.scala:25)
[error] test.PhotoManagementSpec$$anonfun$1$$anonfun$apply$3.apply(PhotoManagementSpec.scala:25)

If I try to replace the deprecated routeAndCall with just route (and remove the Option around result), I get a compile error stating that it can't write an instance of MultipartFormData[TemporaryFile] to the HTTP response.

What's the right way to design this test in Play 2.1 with Scala?


Edit: Tried to modify the code to test just the controller:

"Application" should {

"Upload Photo" in {

   val data = new MultipartFormData(Map(), List(
   FilePart("qqfile", "message", Some("Content-Type: multipart/form-data"), 
    TemporaryFile(getClass().getResource("/test/photos/DSC03024.JPG").getFile()))
), List())

   val result = controllers.Photo.upload()(FakeRequest(POST, "/admin/photo/upload",FakeHeaders(),data))


   status(result) must equalTo(OK)
   contentType(result) must beSome("text/html")
   charset(result) must beSome("utf-8")
   contentAsString(result) must contain("Hello Bob")
  }

But I now get a type error on all the test conditions around the results like so:

[error]  found   : play.api.libs.iteratee.Iteratee[Array[Byte],play.api.mvc.Result]
[error]  required: play.api.mvc.Result

I don't understand why I'm getting an Interator for byte arrays mapped to Results. Could this have something to do with how I'm using a custom body parser? My controller's definition looks like this:

def upload = Action(CustomParsers.multipartFormDataAsBytes) { request =>

  request.body.file("qqfile").map { upload =>

Using the form parser from this post: Pulling files from MultipartFormData in memory in Play2 / Scala

like image 557
djsumdog Avatar asked Feb 28 '13 11:02

djsumdog


People also ask

How do I upload a file to Scala?

Uploading files in a form using multipart/form-data The standard way to upload files in a web application is to use a form with a special multipart/form-data encoding, which lets you mix standard form data with file attachment data. Note: The HTTP method used to submit the form must be POST (not GET ).


1 Answers

In Play 2.6.x you can write test cases in the following way to test file upload API:

class HDFSControllerTest extends Specification {
  "HDFSController" should {
    "return 200 Status for file Upload" in new WithApplication {

      val tempFile = SingletonTemporaryFileCreator.create("txt","csv")
      tempFile.deleteOnExit()

      val data = new MultipartFormData[TemporaryFile](Map(),
      List(FilePart("metadata", "text1.csv", Some("text/plain"), tempFile)), List())

      val res: Option[Future[Result]] = route(app, FakeRequest(POST, "/api/hdfs").withMultipartFormDataBody(data))
      print(contentAsString(res.get))
      res must beSome.which(status(_) == OK)
   }
  }
}
like image 187
Manish Avatar answered Sep 17 '22 15:09

Manish