I am using spring 3.2 mock mvc to test my controller.My code is
@Autowired private Client client; @RequestMapping(value = "/user", method = RequestMethod.GET) public String initUserSearchForm(ModelMap modelMap) { User user = new User(); modelMap.addAttribute("User", user); return "user"; } @RequestMapping(value = "/byName", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody String getUserByName( @RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName, @ModelAttribute("userClientObject") UserClient userClient) { return client.getUserByName(userClient, firstName, lastName); } and I wrote following test:
@Test public void testGetUserByName() throws Exception { String firstName = "Jack"; String lastName = "s"; this.userClientObject = client.createClient(); mockMvc.perform(get("/byName") .sessionAttr("userClientObject", this.userClientObject) .param("firstName", firstName) .param("lastName", lastName) ).andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$[0].id").exists()) .andExpect(jsonPath("$[0].fn").value("Marge")); } what i get is
java.lang.AssertionError: Status expected:<200> but was:<400> at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89) at org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:546) at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141) Why this happens? Is it right way to pass the @RequestParam
3 Answers
When i analyzed your code. I have also faced the same problem but my problem is if i give value for both first and last name means it is working fine. but when i give only one value means it says 400. anyway use the .andDo(print()) method to find out the error
public void testGetUserByName() throws Exception { String firstName = "Jack"; String lastName = "s"; this.userClientObject = client.createClient(); mockMvc.perform(get("/byName") .sessionAttr("userClientObject", this.userClientObject) .param("firstName", firstName) .param("lastName", lastName) ).andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$[0].id").exists()) .andExpect(jsonPath("$[0].fn").value("Marge")); } If your problem is org.springframework.web.bind.missingservletrequestparameterexception you have to change your code to
@RequestMapping(value = "/byName", method = RequestMethod.GET) @ResponseStatus(HttpStatus.OK) public @ResponseBody String getUserByName( @RequestParam( value="firstName",required = false) String firstName, @RequestParam(value="lastName",required = false) String lastName, @ModelAttribute("userClientObject") UserClient userClient) { return client.getUserByName(userClient, firstName, lastName); } 2If anyone came to this question looking for ways to add multiple parameters at the same time (my case), you can use .params with a MultivalueMap instead of adding each .param :
LinkedMultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>() requestParams.add("id", "1"); requestParams.add("name", "john"); requestParams.add("age", "30"); mockMvc.perform(get("my/endpoint").params(requestParams)).andExpect(status().isOk()) @ModelAttribute is a Spring mapping of request parameters to a particular object type. so your parameters might look like userClient.username and userClient.firstName, etc. as MockMvc imitates a request from a browser, you'll need to pass in the parameters that Spring would use from a form to actually build the UserClient object.
(i think of ModelAttribute is kind of helper to construct an object from a bunch of fields that are going to come in from a form, but you may want to do some reading to get a better definition)
1