I would like to test file uploading by REST API. I found it quite confusing to send file as RequestParam instead of RequestBody.
Controller method:
#PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public
#ResponseBody
ResponseEntity<String> uploadFile(
#RequestParam(name = "file") MultipartFile multipartFile,
#RequestParam(name = "path") String path) {
logger.debug("File upload REST requested");
return new ResponseEntity<>(fileService.uploadFile(
multipartFile, path),
HttpStatus.OK);
}
1.Now I would like to test it and I've used mocks. While debugging it, I see that mock service working but method exactly with this arguments is not invoked, so the test if failed. How could I handle this?
#Test
public void testUploadFile() throws Exception {
String mockName = "mock";
MockMultipartFile mockMultipartFile = new MockMultipartFile(mockName, mockName.getBytes());
when(mockFileService.uploadFile(mockMultipartFile, rootDir)).thenReturn("success");
mockMvc.perform(MockMvcRequestBuilders.fileUpload("/files/upload")
.file("file", mockMultipartFile.getBytes())
.param("path", rootDir))
.andExpect(status().isOk())
.andExpect(content().string("success"));
verify(mockFileService, times(1)).updateFile(mockMultipartFile, rootDir);
verifyNoMoreInteractions(mockFileService);
}
2.How could I test this with Postman? I see that I can send file in Body, but how could I send it as param?
EDIT:
I've changed the method, but the problem is not there:
Argument(s) are different! Wanted:
mockFileService.uploadFile(
org.springframework.mock.web.MockMultipartFile#61bd0845,
"/"
);
Looks like method are using 2 instances of MockMultipartFile. And the second question is still open, how could this method be tested from Postman?
Yes, the test case fails, because
the problem is in your test case at the end, you are verifying the call to updateFile() which is incorrect as in your controller you are using uploadFile(), you MUST use the same method to verify.
So, you need to change the verify line as below:
verify(mockFileService, times(1)). uploadFile(mockMultipartFile, rootDir);
In other words, Mockito verify validates the number of times a method is invoked as you are trying to verify the call on a different method (not being used in controller), it is failing.
Related
I an creating an endpoint with spring boot...i can upload image to folder and save it via postman everythink works good.
i have a problem with get method when i am adding the value #RequestMapping value = "getImage/{imageName:.+}" in postman i add http://localhost:8080/api/images/getImage/{burger+png}
is that corect ???
#RequestMapping(value = "api/images")
public class ImageController {
#Autowired
public ImageService imageService;
#PostMapping(value ="upload")
public ResponseEntity uploadImage(#RequestParam MultipartFile file){
return this.imageService.uploadToLocalFileSystem(file);
}
#GetMapping(
value = "getImage/{imageName:.+}",
produces = {MediaType.IMAGE_JPEG_VALUE,MediaType.IMAGE_GIF_VALUE,MediaType.IMAGE_PNG_VALUE}
)
public #ResponseBody byte[] getImageWithMediaType(#PathVariable(name = "imageName") String fileName) throws IOException {
return this.imageService.getImageWithMediaType(fileName);
}
}
what should be the correct request url ???
It seems like it's reaching the backend fine, but failing to find path. Usually API endpoints end with parameters with a slug or query param. You can try either of the following to see if it works:
http://localhost:8080/api/images/getImage/burger.png
http://localhost:8080/api/images/getImage?imageName=burger.png
Keep in mind, you want to make sure that file exists at the path it's mentioning at the very top of the trace in the JSON response. This may depend on how you uploaded the file and with what name.
I am writing unit tests for my controller class. I am using spring webflux. Hence I am writing tests with WebTestClient. Here is my controller method
#PutMapping("/updatedocument/{documentType}")
public ResponseEntity<String> updateDocument(#PathVariable String documentType,
#RequestParam("file") MultipartFile file) {
...................
}
This code is working when I call from Postman or any rest client. I am having difficulty in writing unit test. I am getting
"Required MultipartFile parameter 'file' is not present"
Error . Here is my test method.
#Test
void updateDocument() throws IOException {
.............
MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
multipartBodyBuilder.part("file", new ClassPathResource("somefile"))
.contentType(MediaType.MULTIPART_FORM_DATA)
webTestClient.put()
.uri("/customer/updatedocument/ID")
.body(BodyInserters.fromMultipartData(multipartBodyBuilder.build()))
.exchange()
.expectStatus().isOk();
}
Any suggestion is much appreciated. Please NOTE. I am using WebTestClient and not MovkMvc
I was able to solve this issue. The main culprit is my controller method and not the test method.
Had to change couple of things in controller method. When using spring web flux(reactive) we should use
1.#RequestPart instead of #RequestParam
2. FilePart instead of MultipartFile
So the controller method will look like this.
#PutMapping("/updatedocument/{documentType}")
public ResponseEntity<String> updateDocument(#PathVariable DocumentType documentType,
#RequestPart("file") FilePart filePart) {
.....................
}
You can convert FilePart to File object.
I'm trying to write a unit test checking that user can download a PDF file from a syte. I use spring-boot-starter-parent of version 2.1.2.RELEASE.
Method in controller:
#GetMapping(value = "/download", produces = MediaType.APPLICATION_PDF_VALUE)
#ResponseBody
public ResponseEntity<Resource> downloadFile() {
Resource resource = ...;
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + resource.getFilename() + '"').body(resource);
}
Test method:
#Test
public void shouldFail() throws Exception {
byte[] anyBytes = new byte[]{};
mockMvc.perform(get("/download"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_PDF_VALUE))
.andExpect(content().bytes(anyBytes));
}
In controller method I provide existing PDF-file as a Resource.
Next in test I compare response body with a byte array that is certain not equal to my PDF resource. So test is expected to fail. But it passes.
After some research i found that It is no matter what byte array is provided to content().bytes() - test passes anyway. What is interesting, bytes() method throws AssertionError inside, but it is swallowed somehow.
Is it a bug or I make something wrong?
I am new to wiremock and trying to stub the invocation of the following springboot restful endpoint.
#PostMapping(path = "/template/pdf", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<String> bindData(
#ApiParam(value = "BindDataRequest payload", required = true)
#RequestParam String template, #RequestParam String templateDataAsJson) throws IOException {
//Some code
return ResponseEntity.ok("xyz");
}
**The following basic logic works:**
templatingService.stubFor(
post(urlEqualTo("/template/pdf"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_PDF_GEN).withStatus(200)));
But, i need a way of setting the 2 string request parameters before invoking .willReturn(.....)
I have tried :
templateBinderService.stubFor(
post(urlEqualTo("/template/pdf"))
.withRequestBody(WireMock.equalTo("jixhcjxhcjxhcxhchx"))
.withRequestBody(WireMock.equalTo("nhhhxhxhhhhhxhhhh"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_HTML2PDF_GEN).withStatus(200)));
But got:
org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found
//I have also tried:
templateBinderService.stubFor(
post(urlEqualTo("/template/test"))
.withRequestBody(containing("param1-value"))
.withRequestBody(containing("param2-value"))
.willReturn(aResponse().withBody("i-am-a-response").withStatus(200)));
//I have also tried:
templateBinderService.stubFor(
post(urlEqualTo("/template/test"))
.withRequestBody(equalToJson("{}"))
.willReturn(aResponse().withBody("i-am-a-response").withStatus(200)));
Please help with code snippet or reference.
Since both the parameters template and templateDataAsJson are annotated with #RequestParam, they should be passed accordingly in the wiremock stub as below.
templatingService.stubFor(
post(urlEqualTo("/template/pdf?template=value1&templateDataAsJson=value2"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_PDF_GEN).withStatus(200)));
where value1 and value2 are the respective values for both parameters.
This question has been asked before and I have tried their solution but that doesn't work for me, I am using MockMvc to unit test content type of my rest call.
I am getting this exception:
java.lang.AssertionError: Content type not set
While I'm setting it in my search method using produces attribute.
This is the method where I am initializing the mocks:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(restController, "luceneSearchEnabled", true);
mockMvc = standaloneSetup(restController).build();
}
This is my test method:
#Test
public void pmmSearchContentTypeTest() throws Exception {
mockMvc
.perform(get("/api/v1/pmm").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.andReturn();
}
This is my search method where I am setting content type:
#RequestMapping(value = "/api/" + REST_API_VERSION + "/" + ONE_INTERFACE, method = RequestMethod.GET, produces ={MediaType.APPLICATION_JSON_VALUE})
#ResponseBody
public String pmmSearch() { ... }
I don't know what is wrong here.
I faced the same error and found that , the mock service for this controller method returns null. change mock service method to return values for any() input and test this to get rid of this error.
when(service.method(any())).thenReturn(someElement);
someElement was null earlier causing this error case
Figured it out myself
Instead of using the mock object of retcontroller here
mockMvc = standaloneSetup(restController).build();
I had to use a real object
mockMvc = standaloneSetup(new RestController()).build();
and in order to avoid spring validation error I had to use complete path here
mockMvc
.perform(get("/api/v1/pmm/search{}").contentType(MediaType.APPLICATION_JSON))
If the response returns null, you can get that error, as it says #stuti-verma.
It happened to me right now.
The case: In my test, I was sending a json to the controller, but the object that I used to generate the mocked response didn't have the equals/hashCode implemented. So, it will never match with the received json.
#RequestBody anObject
mock.theMethod(anObject).thenReturn(theResponse)
anObject must have equals/hashCode to be able to be compared
In my case, I had to set the content type returned by the request in the ResponseEntity itself:
PaymentResponse paymentResponse = makePaymentService.makePayment(paymentRequest);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<>(paymentResponse, HttpStatus.OK);
see java.lang.AssertionError: Content Type Not Set - Spring Controller JUnit Tests