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();
}
EECOLOR
  • 11,184
  • 3
  • 41
  • 75
angelokh
  • 9,426
  • 9
  • 69
  • 139

4 Answers4

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

DamnWidget
  • 1,397
  • 2
  • 10
  • 16
  • Why callAction is required for withFormUrlEncodeBody? routeAndCall should also work. routeAndCall(fakeRequest(POST, "/route").withFormUrlEncodedBody(map)); – angelokh Jun 07 '12 at 19:45
  • Mutlipartformdata might work for for scala with you method. However, for java, withFormUrlEncodedBody wouldn't allow a map with value in Object type. – angelokh Jun 07 '12 at 19:49
  • 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. – DamnWidget Jun 07 '12 at 21:12
  • Is not working? Sorry but I dont know the Java API for Play (or Java lanaguage) I'm Python/Scala developer – DamnWidget Jun 08 '12 at 09:37
  • 1
    You cannot map HashMap() to Map – FrEaKmAn Jan 31 '14 at 14:57
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.

jazmit
  • 5,170
  • 1
  • 29
  • 36
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);
}
Kris
  • 4,595
  • 7
  • 32
  • 50
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);
makson
  • 1,975
  • 3
  • 23
  • 31