Why is the test fails though being called with right parameters? - java

I have test, I simplified it to the point it looks like this ( code below ). Objectmapper works fine in tests in the same class.
#Test
void shouldUpdateVote_whenPut() throws Exception {
Mockito.when(voteService.update(5, VOTE_CREATION_ADRIANO)).thenReturn(VOTE_RESPONSE_ADRIANO);
mockMvc.perform(
put("/vote/admin/5")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(VOTE_CREATION_ADRIANO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$", notNullValue()));
}
Test fails every time with
java.lang.AssertionError: No value at JSON path "$"
I decided to check if the method is called with needed parameters.
#Test
void shouldUpdateVote_whenPut() throws Exception {
Mockito.when(voteService.update(5, VOTE_CREATION_ADRIANO)).thenReturn(VOTE_RESPONSE_ADRIANO);
mockMvc.perform(
put("/vote/admin/5")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(VOTE_CREATION_ADRIANO)));
Mockito.verify(voteService, times(1)).update(eq(5), refEq(VOTE_CREATION_ADRIANO));
}
And it is successfull. The question is, why does the test fail? Is the problem with mockito.when?
Here is the controller method under test. Controller works fine, I've checked it many times.
#PutMapping("/{id}")
public VoteResponseDTO updateAnyVote(#PathVariable int id, #RequestBody #Valid VoteCreationDTO voteCreationDTO,
BindingResult bindingResult) {
throwExceptionIfBindingResultHasErrors(bindingResult);
return voteService.update(id, voteCreationDTO);
}

Related

MockMvc can't validate with param #DateValid

I'm using MockMvc to test my method that has a date parameter. The parameter is annotated with #DateValid but MockMvc doesn't trigger the validator and returns success when I input a wrong date.
StudentControler
public ResponseEntity<?> getStudents(#PathVariable("id") String studentId,
#RequestParam("birthDate") #DateValid String Date) {
//do something
}
Test
public class StudentController extends AbstractControllerTest {
#Test
public void testStudents_validRequest() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("birthDate","aaaa");
MvcResult result = getMvc().perform(get("/student/{studentId}", "test")
.params(params)
.characterEncoding(StandardCharsets.UTF_8.name())
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json(mapToJson(studentResDto)))
.andReturn();
verify(studentService).getStudentId(anyString(), anyString());
log(log, result);
}
}
I do not understand why because when I test using Postman it works as expected. Postman does validate but MockMvc does not?
I using Spring-Boot 2.1.3
I can think of 2 problems here:
The validation annotation class is not loaded properly in your test. This seems to happen primarily when combining Spring validation with Hibernate validation (see also this question on how to fix that.
Your test is not setup properly. Could it be that you are not fully loading your controller in your mock test? Perhaps you are mocking the controller accidentally?

Test POST method that return ResponseEntity<> in Spring

I'm trying to test my POST method that returns ResponseEntity<> in service class:
public ResponseEntity<Customer> addCustomer(Customer customer) {
[validation etc...]
return new ResponseEntity<>(repository.save(customer), HttpStatus.OK);
}
What I'm doing:
#Test
public void addCustomer() throws Exception {
String json = "{" +
"\"name\": \"Test Name\"," +
"\"email\": \"test#email.com\"" +
"}";
Customer customer = new Customer("Test Name", "test#email.com");
when(service.addCustomer(customer))
.thenReturn(new ResponseEntity<>(customer, HttpStatus.OK));
this.mockMvc.perform(post(CustomerController.URI)
.contentType(MediaType.APPLICATION_JSON)
.content(json)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.name", is("Test Name")))
.andExpect(jsonPath("$.email", is("test#email.com")))
.andExpect(jsonPath("$.*", hasSize(3)))
.andDo(print());
}
When I run the test I've receiving:
java.lang.AssertionError: No value at JSON path "$.id"
and Status = 200. So as far as I understand Mockito is not returning the object. The other methods like GET work perfectly fine, but they return the object, not the ResponseEntity<>. What I'm doing wrong and how can I fix that?
The problem is that you have created a Customer in test code, this Customer is different from the Customer in production code.
So Mockito cannot match the two Customer, and cause when/thenReturn expression to fail. Thus service.addCustomer return a null and you get AssertionError in test result.
You can use any() matcher to solve this problem:
when(service.addCustomer(any())).thenReturn(.....);

Spring controller test fails with 404 when #PathVariable is a string

I am trying to test a Spring controller method - the method is at the end of the post and the test class below that. I've stripped it back a bit to try and narrow down the problem.
When I run the test as is it fails:
java.lang.AssertionError: Status
Expected :200
Actual :404
If I edit the mockMvc.perform as follows then the test passes, I don't even have to change the #PathVariables in the controller to be Longs:
mockMvc.perform(get(ApplicationEndPoints.GET_CCS_NAME_AND_ADDRESS_AJAX, 1L, 2L))
.andExpect(status().isOk());
The controller method itself works fine and returns JSON as expected. Can I just use these Long values and expect the test to be ok or how can I get it to work with Strings?
I should add that I'm a total testing noob. Thanks!
controller method:
#PreAuthorize("hasAuthority('auditor')")
#RequestMapping(value = ApplicationEndPoints.GET_APPLICANT_DATA, method = RequestMethod.GET)
#ResponseBody
public ApplicantData getNameAndAddress(#PathVariable("businessId") String businessId, #PathVariable("date") String date) {
//Date d = Date.valueOf(date);
ApplicantParams params = new ApplicantParams();
//params.setBusinessId(businessId);
//params.setApplicationReceivedDate(d);
params.setRoleId(ADDRESS_ROLE.HR.getRoleId());
return applicantService.getApplicantData(params);
}
test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ApplicationTestConfig.class})
#WebAppConfiguration
public class ClientDetailAjaxControllerTest {
#InjectMocks
private ClientDetailAjaxController clientDetailAjaxController;
private MockMvc mockMvc;
private ApplicantServiceInterface<Applicant> applicantService = Mockito.mock(ApplicantServiceImpl.class, Mockito.RETURNS_DEEP_STUBS);
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(clientDetailAjaxController).build();
}
#Test
public void getNameAndAddress() throws Exception {
Mockito.when(applicantService.getApplicantData(Mockito.any(ApplicantParams.class)))
.thenReturn(ApplicationTestData.getApplicantData());
mockMvc.perform(get(ApplicationEndPoints.GET_APPLICANT_DATA, Mockito.anyString(), Mockito.anyString()))
.andExpect(status().isOk());
Mockito.verify(applicantService, Mockito.times(1)).getApplicantData(Mockito.any(ApplicantParams.class));
Mockito.verifyNoMoreInteractions(applicantService);
}
}
EDIT: I have cleared up one or two things in response to comments...
404 tells you that mockMVC cannot match the controller method you're trying to call.
I'm noticing that in your controller, the path is ApplicationEndPoints.GET_APPLICANT_DATA, while in the test you've shown the path is ApplicationEndPoints.GET_CCS_NAME_AND_ADDRESS_AJAX.
Nevertheless - don't use Mockito.anyString() in place of parameter values you have to supply to your RequestBuilder in the mockMVC perform method.
Here's an idea how code should look like (derived from your example):
To test this controller method:
#RequestMapping(value = "/applicant/name-and-address/", method = RequestMethod.GET)
public ApplicantData getNameAndAddress(#PathVariable("businessId") String businessId, #PathVariable("date") String date) {
// some code
}
You need to do something like:
mockMvc.perform(get("/applicant/name-and-address/{businessId}/{date}", "myBusinessId", "myDateAsString")).andExpect(status().isOk());
The difference is that you have to pass actual string values, not Mockito.anyString().
Some other notes:
If your URL path variable has the same name as the parameter you're binding it to, you can write #PathVariable String id, instead of #PathVariable("id") String id.
you can use #GetMapping in place of #RequestMapping for GET method, #PostMapping for POST etc.

How can I write a junit test to that is dependent on index page?

I have a application, using java, thymeleaf, and springboot. On the home page localhost:8080 users must enter a value to be redirected to the second page "localhost:8080/getValues"
How can I write a junit test so that I can test the expected values? Currently my tests are coming up as 404 page not found because it is dependent on the value that user inputs on the home page.
Test
#Test
public void test() throws Exception {
this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andDo(print());
//test passes
}
#Test
public void testVals() throws Exception {
this.mockMvc.perform(post("getValues"))
.andExpect(status().isNotFound()) //passes
.andExpect(model().attributeExists("webHist")); //fails //no modelandviewfound
}
Controller
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(Locale locale) throws MalformedURLException {
ModelAndView model = new ModelAndView("index");
return model;
}
#RequestMapping(value = "/getValues", method = RequestMethod.POST)
public ModelAndView getValues(Info info) throws MalformedURLException {
ModelAndView model = new ModelAndView("getValues");
model.addObject("userID", info.userID());
Customer custinfo = index.readXML(info.userID());
model.addObject("custinfo", custinfo);
model.addObject("webHist", Web_HistoryRepo.getAll(info.userID()));
return model;
}
About the unit test, you are not sending the Info info
you are missing the content() in your unit, it should something like
this.mockMvc.perform(post("getValues"))
.contentType(MediaType.APPLICATION_JSON)
.content(INFO_IN_JSON_FORM)
.andExpect(status().isNotFound()) //passes
.andExpect(model().attributeExists("webHist"));
if it still does not work add .andDo(print()) to the end of the test, so that you will receive more details about result.
Next I do not how your whole Controller looks like, if it is annotated with #RestController, if not you should add #RequestBody to the getValues() method so that Info would be mapped from Json.
If it comes to the SPA, you do not return ModelAndView, but Json responses, and your frontend interprets it.

Spring MVC test framework returning inconsistent results for async controller tests

Using Spring MVC test frameworks standaloneSetup mode to test asynchronous methods calls, I'm getting inconsistent results. The following test can pass in my IDE, but then fail when run using ANT, but then at times will pass when run using ANT, or fail in the IDE. The contents of the second call will just return and empty string, or return the expected response.
If I add .andDo(print) to the first call, or add a Sleep of say 500ms between the 2 mockMvc.perform calls, the test will pass.
Has anybody else encountered this?
Controller Route
#RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public final Callable<ResponseEntity<List<Integer>>> getEntries(
#RequestParam(value = "limit", defaultValue = "100") final int limit) {
return new Callable<ResponseEntity<List<Integer>>>() {
#Override
public ResponseEntitcany<List<Integer>> call() {
return new ResponseEntity<List<Integer>>(service.findTopEntries(limit), HttpStatus.OK);
}
};
}
Test
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
#Test
public void testJSONResponse() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(get(this.basePath)
.accept(MediaType.APPLICATION_JSON))
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk())
.andExpect(content().string("[]"));
}
You need to call asyncStarted
MvcResult mvcResult = this.mockMvc.perform(get(this.basePath)
.accept(MediaType.APPLICATION_JSON)).andExpect(request().asyncStarted())
.andReturn();
Though this still gave inconsistent results at times for me
It helped me to invoke dummy
mvcResult.getAsyncResult();
before checking the result. Otherwise I get response 200 instead of 404. Spring 4.0.6.
final MvcResult mvcResult = this.mockMvc.perform(get("/api/buildings/{id}", key.toString())
.accept(MediaType.APPLICATION_JSON))
.andExpect(request().asyncStarted())
.andReturn();
mvcResult.getAsyncResult();
this.mockMvc.perform(asyncDispatch(mvcResult))
.andDo(print())
.andExpect(status().isNotFound());
There is known bug in spring mvc test framework, https://jira.springsource.org/browse/SPR-10838.
Try 2.3.5-SNAPSHOT, It seems to be fixed there

Categories