when I am trying to write the junit for my controller class, I am getting 400 bad request.
In console , i can see below error:
logException Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
this is my Junit
#Test
void testExcelFile() throws Exception {
FileInputStream inputFile = new FileInputStream("path of the file");
MockMultipartFile file = new MockMultipartFile("file", "myexcelFile.xlsx", "multipart/form-data", inputFile);
Mockito.when(service.upload((MultipartFile) file)).thenReturn("received");
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/uploadData",file)
.param("file",file.getName()).contentType(MediaType.MULTIPART_FORM_DATA);
MvcResult result =
mockMvc.perform(requestBuilder).andExpect(status().isAccepted()).andReturn();
assertEquals(HttpStatus.ACCEPTED.value(), result.getResponse().getStatus());
}
This is my controller class
#PostMapping("/uploadData")
public ResponseEntity<String> save(#RequestParam(required = true) MultipartFile file) {
if(ExcelHelper.checkExcelFormat(file)) {
return new ResponseEntity<>(service.upload(file),HttpStatus.ACCEPTED);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Please upload excel file only");
}
Please help what I am doing wrong. Thanks in advance.
Related
I'm new to MockMVC. I've successfully written some basic tests, but I got stuck on trying to test an use case with the endpoint that requires a POST request with two parameters - a POJO and an array of MultipartFile. The test is written as such:
#Test
public void vytvorPodnetTest() throws Exception {
var somePojo = new SomePojo();
somePojo.setSomeVariable("test_value");
var roles = List.of("TEST_USER");
var uid = "00000000-0000-0000-0000-000000000001";
MockMultipartFile[] attachments = {new MockMultipartFile("file1.txt", "file1.txt", "text/plain", "file1 content".getBytes()),
new MockMultipartFile("file2.txt", "file2.txt", "text/plain", "file2 content".getBytes())};
MockMultipartHttpServletRequestBuilder builder = MockMvcRequestBuilders.multipart("/some-pojo/create");
builder.with(req - {
req.setMethod("POST");
return req;
});
MvcResult result = mockMvc.perform(builder.file(attachments[0]).file(attachments[1])
.param("SomePojo", new ObjectMapper().writeValueAsString(somePojo))
.file(attachment[0])
.with(TestUtils.generateJWTToken(uid, roles)))
.andExpect(status.isOk())
.andReturn();
}
The controller method is as follows:
#PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public UUID createPojo(
#RequestPart(value = "SomePojo") SomePojo somePojo,
#RequestPart(value = "attachments", required = false) MultipartFile[] attachments) {
return pojoService.create(somePojo, attachments);
}
It stops here, before reaching the service. I've tried adding the files both as a param "attachments" and like shown above, but all I get is "400 Bad Request"
Finally found the way to send the parameters as MockMultipartFile from MockMVC to the controller:
MockMultipartFile pojoJson = new MockMultipartFile("SomePojo", null,
"application/json", JsonUtils.toJSON(podnet).getBytes());
mockMvc.perform(MockMvcRequestBuilders.multipart("/some-pojo/create")
.file(pojoJson)
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.with(new TestUtils().generateJWTToken(uid, roles)))
.andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
Using Spring boot 2 and Spring mvc. I am trying to test my rest controller using mockMvc
#PostMapping(
value = "/attachment")
public ResponseEntity attachment(MultipartHttpServletRequest file, #RequestBody DocumentRequest body) {
Document document;
try {
document = documentService.process(file.getFile("file"), body);
} catch (IOException | NullPointerException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
return ResponseEntity.accepted().body(DocumentUploadSuccess.of(
document.getId(),
"Document Uploaded",
LocalDateTime.now()
));
}
I could attach the file successfully on my test but know I added a body and I can't receive both attached
#Test
#DisplayName("Upload Document")
public void testController() throws Exception {
byte[] attachedfile = IOUtils.resourceToByteArray("/request/document-text.txt");
MockMultipartFile mockMultipartFile = new MockMultipartFile("file", "",
"text/plain", attachedfile);
DocumentRequest documentRequest = new DocumentRequest();
documentRequest.setApplicationId("_APP_ID");
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.fileUpload("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest));
MvcResult result = mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isAccepted())
.andDo(MockMvcResultHandlers.print()).andReturn();
JsonNode response = objectMapper.readTree(result.getResponse().getContentAsString());
String id = response.get("id").asText();
Assert.assertTrue(documentRepository.findById(id).isPresent());
}
I got 415 status error
java.lang.AssertionError: Status expected:<202> but was:<415>
Expected :202
Actual :415
How could I fix it?
You're getting status 415: unsupported media type.
You needed to changed add contentType() of the request which the controller accepts.
If your controller accepts application/json:
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.multipart("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest))
.contentType(MediaType.APPLICATION_JSON);// <<<
I want to test my Spring Controller that has input json and multipart file, however even if the function works, I can't get the test works
I tried using MockMvcRequestBuilders.fileUpload but the test always get 405
The controller:
#PutMapping(value = "/upload", consumes = {"multipart/form-data"})
public BaseResponse<SomeModel> updateSomeModelContent(
#ApiIgnore #Valid #ModelAttribute MandatoryRequest mandatoryRequest,
#PathVariable("id") String id,
#RequestParam("file") MultipartFile file,
#RequestParam("json") String json) throws IOException {
final CommonSomeModelRequest request = JSONHelper.convertJsonInStringToObject(json, CommonSomeModelRequest.class);
return makeResponse(someModelSer.updateContent(id, request, mandatoryRequest, file));
}
The test:
#Test
public void updateCountryContentSuccessTest() throws Exception {
MockMultipartFile file1 = new MockMultipartFile("file", "filename-1.jpeg", "image/jpeg", "some-image".getBytes());
MockMultipartFile file2 = new MockMultipartFile("json", "", "application/json","{\"exampleAttr\": \"someValue\"}".getBytes());
when(this.someModelService
.updateContent(id, request, MANDATORY_REQUEST, file1))
.thenReturn(someModelUpdatedContent);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders
.fileUpload("/upload/{id}", id)
.file(file1)
.file(file2)
.requestAttr("mandatory", MANDATORY_REQUEST);
this.mockMvc.perform(builder)
.andExpect(status().isOk());
verify(this.someModelService)
.updateContent(id, request, MANDATORY_REQUEST, file1);
}
The result status is always 405, I don't know how to make it 200
MockMvcRequestBuilders.multipart(...) create MockMultipartHttpServletRequestBuilder which support only POST.
But in your controller you use POST. You should change PUT to POST mapping in the rest controller.
Also according to RFCs we should use POST instead of PUT on multipart upload.
Have a look at Spring MVC Framework: MultipartResolver with PUT method
I use Jhipster and this is a controller method:
Controller:
#RequestMapping(value = UPLOAD_URL, method = {RequestMethod.POST},
headers = {"content-type=multipart/mixed", "content-type=multipart/form-data"},
consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadWithMetaData(#RequestPart(value = "file") MultipartFile file,
#RequestPart(value = "documentDTO") DocumentDTO documentDTO,
Locale locale) throws IOException, URISyntaxException, JSONException {
// business logic
}
Essentially I want to post a file and also a json object.
I my integration test, I can verify that it works as expected:
Integration test:
DocumentDTO documentDTO = getDocumentDTOMockFile();
Long originId = originRepository.findAll().stream().findFirst().get().getId();
documentDTO.setOriginId(originId);
MockMultipartFile jsonFile = new MockMultipartFile("documentDTO", "", "application/json",
jsonUtils.toJson(documentDTO, null).getBytes());
restClientMockMvc
.perform(MockMvcRequestBuilders.fileUpload("/api/v1/documents/upload")
.file(fstmp)
.file(jsonFile))
.andDo(MockMvcResultHandlers.log())
.andExpect(status().isOk());
}
Angular frontend:
let fd: FormData = new FormData();
let file = fileForm.files[0];
fd.append("file", file);
let documentDTO = JSON.stringify(document);
fd.append("documentDTO",new Blob([JSON.stringify({
"documentDTO": documentDTO})], {
type: "application/json"
})
);
his.httpClient.post("/api/v1/documents/upload", fd ).subscribe(request => {
console.log("request", request);
});
I got an interceptor that sets the content-type in the request headers to:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundary4PnIOSOLe5Djj95R
This is how the Request payload looks like:
This is the spring boot log message:
Resolved exception caused by Handler execution: org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
This is the response I see in the browser:
{
"type" : "http://www.jhipster.tech/problem/problem-with-message",
"title" : "Bad Request",
"status" : 400,
"detail" : "Required request part 'file' is not present",
"path" : "///api/v1/documents/upload",
"message" : "error.http.400"
}
What I've tried:
setting content-type to 'Content-Type' : 'multipart/mixed' => result same
Creating a pojo with the dto and the file, using #ModelAttribute => same error
Then I checked if I got a Multipart Resolver, got it
I'm out of ideas, someone any suggestions?
Post as a multipart-form from the JavaScript and use something like this:
final WebRequest webRequest,
#RequestParam("fileContent") final MultipartFile fileContent,
#RequestParam("inputJson") String inputJsonString
as the parameters.
The WebRequest is useful if you need to access the session.
I have controller, which handles multiple file upload:
#PostMapping("/import")
public void import(#RequestParam("files") MultipartFile[] files, HttpServletRequest request) {
assertUploadFilesNotEmpty(files);
...
}
And I want to test it
#Test
public void importTest() throws Exception {
MockMultipartFile file = new MockMultipartFile("file", "list.xlsx", MIME_TYPE_EXCEL, Files.readAllBytes(Paths.get(excelFile.getURI())));
mvc.perform(fileUpload("/import").file(file).contentType(MIME_TYPE_EXCEL)).andExpect(status().isOk());
}
Problem is that MockMvc, creates MockHttpRequest with multipartFiles as a name for param that holds uploaded files. And my controller expects those files will be in 'files' param.
Is it possible to tell spring that multiple files should be passed in request under given name?
Create two MockMultiPartFile instances with name files
Complete working example with added Json request body as well as multiple files below :
#PostMapping(consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
public void addProduct(#RequestPart(value="addProductRequest") #Valid AddUpdateProductRequest request,
#RequestPart(value = "files") final List<MultipartFile> files) throws Exception{
request.setProductImages(files);
productService.createProduct(request);
}
#Test
public void testUpdateProduct() throws Exception {
AddUpdateProductRequest addProductRequest = prepareAddUpdateRequest();
final InputStream inputStreamFirstImage = Thread.currentThread().getContextClassLoader().getResourceAsStream("test_image.png");
final InputStream inputStreamSecondImage = Thread.currentThread().getContextClassLoader().getResourceAsStream("test_image2.png");
MockMultipartFile jsonBody = new MockMultipartFile("addProductRequest", "", "application/json", JsonUtils.toJson(addProductRequest).getBytes());
MockMultipartFile file1 = new MockMultipartFile("files", "test_image.png", "image/png", inputStreamFirstImage);
MockMultipartFile file2 = new MockMultipartFile("files", "test_image2.png", "image/png", inputStreamSecondImage);
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
mockMvc.perform(MockMvcRequestBuilders.fileUpload("/add-product")
.file(file1)
.file(file2)
.file(jsonBody)
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
.andDo(MockMvcResultHandlers.log())
.andExpect(ok)
.andExpect(content().string("success"));
}