Test MultipartFormData in Play 2.0 FakeRequest
Asked Answered
C

4

9

I'm trying to create a function test for a Play 2 controller which takes multipart form data as input. There is no method currently in FakeRequest to support multipart form POST. What other ways to test this controller?

Map<String, Object> map = new HashMap<String, Object>();
map.put("param1", "test-1");
map.put("param2", "test-2");
map.put("file", file)
Result result = routeAndCall(fakeRequest(POST, "/register").withFormUrlEncodedBody(map));// NO SUCH METHOD

EDIT: This is the workaround I did to test multipart.

    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost("http://localhost:3333/blobupload");

    FileBody imageFile = new FileBody(new File("test/resources/test-1.jpg"));
    StringBody guid1 = null;
    StringBody guid2 = null;
    try {
        guid1 = new StringBody("GUID-1");

    } catch (UnsupportedEncodingException e1) {
        e1.printStackTrace();
    }

    MultipartEntity reqEntity = new MultipartEntity();
    reqEntity.addPart("key1", imageFile);
    reqEntity.addPart("key2", guid1);

    httppost.setEntity(reqEntity);

    HttpResponse response;
    try {
        response = httpclient.execute(httppost);
        HttpEntity resEntity = response.getEntity();

        assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
    } catch (ClientProtocolException e) {
        e.printStackTrace();
} catch (IOException e) {
        e.printStackTrace();
}
Chalkstone answered 5/6, 2012 at 1:11 Comment(0)
B
7

You should use callAction to use withFormUrlEncodedBody

@Test
public void testMyAction() {
    running(fakeApplication(), new Runnable() {
        public void run() {                
            Map<String,String> data = new HashMap<String, Object>();
            data.put("param1", "test-1");
            data.put("param2", "test-2");
            data.put("file", file);

            Result result = callAction(
                controllers.whatever.action(),
                fakeRequest().withFormUrlEncodedBody(data)
            )
            ...
         }
     }
}

I use only Scala api for Play Framework 2 but I dont think you can test the multipart form using withFormUrlEncodedBody.

You can do in this way in Scala:

import play.api.libs.Files._
import play.api.mvc.MultipartFormData._

class MyTestSpec extends Specification {

    "mytest should bla bla bla" in {
        running(FakeApplication(aditionalConfiguration = inMemoryDatabase())) {
            val data = new MultipartFormData(Map(
                ("param1" -> Seq("test-1")),
                ("param2" -> Seq("test-2"))
            ), List(
                FilePart("payload", "message", Some("Content-Type: multipart/form-data"), play.api.libs.Files.TemporaryFile(new java.io.File("/tmp/pepe.txt")))
    ), List(), List())

            val Some(result) = routeAndCall(FakeRequest(POST, "/route/action", FakeHeaders(), data))
            ...
        }
    }
}

I guess you can translate it to Java, I don't know how to code it in Java sorry.

P.D: Sorry for my English I'm still learning

Brogue answered 7/6, 2012 at 14:28 Comment(5)
Why callAction is required for withFormUrlEncodeBody? routeAndCall should also work. routeAndCall(fakeRequest(POST, "/route").withFormUrlEncodedBody(map));Chalkstone
Mutlipartformdata might work for for scala with you method. However, for java, withFormUrlEncodedBody wouldn't allow a map with value in Object type.Chalkstone
I don't know why callAction is required on Java flavour but seems like you can only call fakeRequest().withFormUrlEncodeBody with callAction, anyway, I don't know much about Java language so I can be completely wrong. I dont think you need to use withFormUrlEncodedBody to test your multipart, you should only build the correct POST request.Brogue
Is not working? Sorry but I dont know the Java API for Play (or Java lanaguage) I'm Python/Scala developerBrogue
You cannot map HashMap<String, Object>() to Map<String, String>Triumph
L
2

The easiest way to do this is to use Scala as follows:

val formData = Map(
  "param-1" -> Seq("value-1"),
  "param-2" -> Seq("value-2")
)
val result = routeAndCall(FakeRequest(POST, "/register").copy(body=formData))

This is assuming your controller method is of the form:

def register = Action(parse.tolerantFormUrlEncoded) { ... }

If you really must use Java, you don't have access to named parameters, so the 'copy' method above would have to be called in full. Also be careful to import the scala play.api.test.FakeRequest object, as the Java FakeRequest proxy doesn't have a copy method.

Legumin answered 17/6, 2012 at 10:9 Comment(1)
Can file be allowed in the formData?Chalkstone
T
2

Here is a solution with callAction() in Java to create the multipart/form-data content for a request. It works at least in Play 2.2.3. My content-type was application/zip. You might want to change this.

@Test
public void callImport() throws Exception {
    File file = new File("test/yourfile.zip");
    FilePart<TemporaryFile> part = new MultipartFormData.FilePart<>(
            "file", "test/yourfile.zip",
            Scala.Option("application/zip"), new TemporaryFile(file));
    List<FilePart<TemporaryFile>> fileParts = new ArrayList<>();
    fileParts.add(part);
    scala.collection.immutable.List<FilePart<TemporaryFile>> files = scala.collection.JavaConversions
            .asScalaBuffer(fileParts).toList();
    MultipartFormData<TemporaryFile> formData = new MultipartFormData<TemporaryFile>(
            null, files, null, null);
    AnyContent anyContent = new AnyContentAsMultipartFormData(formData);

    Result result = callAction(
            controllers.routes.ref.ImportExport.import(),
            fakeRequest().withAnyContent(anyContent,
                    "multipart/form-data", "POST"));

    // Your Tests
    assertThat(status(result)).isEqualTo(OK);
}
Tunisia answered 24/1, 2015 at 21:40 Comment(0)
A
0
Map<String, Object> data = new HashMap<String, Object>();
map.put("param1", "test-1");
map.put("param2", "test-2");

  final Http.RequestBuilder request = Helpers.fakeRequest()
                .method(POST)
                .bodyForm(formData)
                .uri("/register");

        final Result result = route(app, request);
Aureomycin answered 11/9, 2017 at 13:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.