After working most of the day I feel like I am fairly close to a solution on how to test a controller method which accepts file uploads from JUnit. My juint test code is as follows:
Map<String, String> postData = makePostMap(uploadForm);
File file = new File("test/resources/shared/uploads/blank.csv");
TemporaryFile temporaryFile = new TemporaryFile(file);
MultipartFormData.FilePart filePath = new MultipartFormData.FilePart(
"file",
"file.csv",
new scala.Some<>("text/csv"),
temporaryFile);
List<MultipartFormData.FilePart> fileParts = Lists.newArrayList(filePath);
scala.collection.immutable.Seq files = JavaConversions.asScalaBuffer(fileParts).toList();
Map<String, scala.collection.immutable.Seq<String>> postData2 = new HashMap<>();
for (String s : postData.keySet()) {
postData2.put(s, JavaConversions.asScalaBuffer(Lists.newArrayList(postData.get(s))).toList());
}
scala.collection.immutable.Map<String, scala.collection.immutable.Seq<String>> scalaMap =
JavaConversions.mapAsScalaMap(postData2).toMap(Predef.<Tuple2<String, scala.collection.immutable.Seq<String>>>conforms());
MultipartFormData formData = new MultipartFormData(scalaMap, files, null, null);
AnyContentAsMultipartFormData body = new AnyContentAsMultipartFormData(formData);
// run
login(employee);
String url = routes.ManageContacts.uploadCsv().url();
FakeRequest fakeRequest = new FakeRequest(POST, url).withBody(body);
fakeRequest = getAuthenticatedRequest(fakeRequest, employee);
result = route(fakeRequest);
assertThat(status(result)).isEqualTo(OK)
However, I get an exception (below) when the FakeRequest is routed to.
[error] Test controllers.ManageContactsTest.testUploadCsv failed: scala.MatchError: AnyContentAsMultipartFormData(MultipartFormData(Map(clearExisting -> List(false), survey -> List(11), bosMode -> List(false)),List(FilePart(file,file.csv,Some(text/csv),TemporaryFile(test/resources/shared/uploads/blank.csv))),null,null)) (of class play.api.mvc.AnyContentAsMultipartFormData), took 0.255 sec
[error] at play.api.test.RouteInvokers$class.jRoute(Helpers.scala:255)
[error] at play.api.test.Helpers$.jRoute(Helpers.scala:403)
[error] at play.api.test.Helpers.jRoute(Helpers.scala)
[error] at play.test.Helpers.route(Helpers.java:445)
[error] at play.test.Helpers.route(Helpers.java:437)
[error] at play.test.Helpers.route(Helpers.java:433)
[error] at controllers.ManageContactsTest.testUploadCsv(ManageContactsTest.java:121)
[error] ...
Diving down into the stack trace, I find the following scala match statement in the file:
/Users/jcreason/bin/playframework-2.3.8/framework/src/play-test/src/main/scala/play/api/test/Helpers.scala:253
def jRoute[T](app: Application, r: FakeRequest[T]): Option[Future[Result]] = {
(r.body: @unchecked) match {
case body: AnyContentAsFormUrlEncoded => route(app, r, body)
case body: AnyContentAsJson => route(app, r, body)
case body: AnyContentAsXml => route(app, r, body)
case body: AnyContentAsText => route(app, r, body)
case body: AnyContentAsRaw => route(app, r, body)
case body: AnyContentAsEmpty.type => route(app, r, body)
//case _ => MatchError is thrown
}
}
Since I'm passing through AnyContentAsMultipartFormData, it throws this exception as it's not handled by the match. Does anyone know how to get around this? Or could point me in the direction of a different solution to this (aside from obvious answers just as selenium)?
For reference, I pulled some of this code from:
http://www.erol.si/2014/02/how-to-test-file-uploads-in-play-framework-java/
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 ). The getRef() method gives you a reference to a TemporaryFile .
Ways to write unit test code for File upload on Controllers: For file upload related testing we need to Mock HTTPContext, HTTPContext. Server and HttpPostedFileBase. These classes handle the file uploading and saving.
This code may be useful:
import static play.test.Helpers.*;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.Test;
import akka.stream.javadsl.Source;
import akka.util.ByteString;
import play.mvc.Http.MultipartFormData.*;
import play.mvc.Http.RequestBuilder;
import play.mvc.Result;
import play.test.*;
class UploadFileTest extends WithApplication {
@Test
public void uploadTest() {
Part<Source<ByteString, ?>> part = new FilePart<>("key", "fileName", "application/octet-stream",
Source.empty());
List<Part<Source<ByteString, ?>>> data = Arrays.asList(part);
RequestBuilder requestBuilder = fakeRequest(controllers.routes.UploadController.upload()).method(POST)
.bodyMultipart(data, mat);
Result result = route(app, requestBuilder);
assertEquals(Helpers.OK, result.status());
}
}
If you want to send not empty file,
instead of Source.empty() use FileIO.fromFile(new File("path/to/file"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With