Mock MVC - Add Request Parameter to test - spring

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

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);
}

If 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)

Related

What should I do in springboot if I use a post request with only one parameter?

No use of map and bean, what is a good solution?
How to get the orderId better
#RequestMapping(value = "/submitTail", method = RequestMethod.POST)
#ResponseBody
public Object generateTailOrder(String orderId) {
}
Use PathVariable if you can add orderId somewhere in URL. Take care of API standards.
Example: /orders/{orderId}/submitTrail
By doing this your API will be more informative and should not be invoked without orderId.
#RequestMapping(value = "/submitTail/{orderId}", method =
RequestMethod.GET)
public Object generateTailOrder(#PathVariable String orderId) {
}
OR
#GetMapping(value = "/submitTail/{orderId}")
public Object generateTailOrder(#PathVariable String orderId) {
}

Can spring map POST parameters by a way other than #RequestBody

I am using #RestControllers with an application where all requests are POST requests ... As I learned from this post , you can't map individual post parameters to individual method arguments, rather you need to wrap all the parameters in an object and then use this object as a method parameter annotated with #RequestBody thus
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestParam(value="idNumber") String idNumber , #RequestParam(value="applicationId") String applicationId) {
return customerService.requestOTP(idNumber, applicationId);
will not work with a POST request of body {"idNumber":"345","applicationId":"64536"}
MY issue is that I have A LOT of POST requests , each with only one or two parameters, It will be tedious to create all these objects just to receive the requests inside ... so is there any other way similar to the way where get request parameters (URL parameters) are handled ?
Yes there are two ways -
first - the way you are doing just you need to do is append these parameter with url, no need to give them in body.
url will be like - baseurl+/requestotp?idNumber=123&applicationId=123
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestParam(value="idNumber") String idNumber , #RequestParam(value="applicationId") String applicationId) {
return customerService.requestOTP(idNumber, applicationId);
second- you can use map as follows
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody Map<String,Object> body) {
return customerService.requestOTP(body.get("idNumber").toString(), body.get("applicationId").toString());
I have change your code please check it
DTO Class
public class DTO1 {
private String idNumber;
private String applicationId;
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
}
Rest Controller Method
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody DTO1 dto){
System.out.println(dto.getApplicationId()+" (------) "+dto.getIdNumber());
return "";
}
Request Type -- application/json
{"idNumber":"345","applicationId":"64536"}
OR
#RequestMapping(value="/requestotp",method = RequestMethod.POST)
public String requestOTP( #RequestBody String dto){
System.out.println(dto);
return "";
}

Spring Boot - How can I pass custom values in HTTP Post api?

I'm new with Spring Boot and I have difficult to understand how can I pass data. For example:
I want pass those data to my server:
{
"code", 1,
"name": "C01"
}
So I have create always a custom Object with code and name as attributes to have this http post api?
#RequestMapping(value = "/new/", method = RequestMethod.POST)
public ResponseEntity<?> createOrder(#RequestBody CustomObject customObject){
...
}
Another solution I see that can be this but I can't pass numbers (int code), right?
#RequestMapping(value = "/new/{code}/{name}", method = RequestMethod.POST)
public ResponseEntity<?> createOrder(#PathVariable("code") int code, #PathVariable("name") String name) {
...
}
Kind regards :)
You can pass code and name as PathVariables just like in your example:
#RequestMapping(value = "/new/{code}/{name}")
public ResponseEntity<?> createOrder(#PathVariable("code") int code, #PathVariable("name") String name) {
...
}
A PathVariable can be an int or a String or a long or a Date, according to the docs:
A #PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so.
You could also define a PathVariable of type Map<String, Object> like this:
#RequestMapping(value = "/new/{code}/{name}")
public ResponseEntity<?> createOrder(#PathVariable("map") Map<String, Object> map) {
Integer code = (Integer) map.get("code");
String name = (String) map.get("name");
...
}
You could even use #RequestParam and supply the data in the form of URL query parameters.
So, there are numerous ways in which data can be passed to a Spring MVC controller (more details in the docs) but I think the convention for posting complex data (by "complex" I mean more than a single piece of state) is to define a request body which contains a serialised form of that complex state i.e. what you showed in the first example in your queston:
#RequestMapping(value = "/new/", method = RequestMethod.POST)
public ResponseEntity<?> createOrder(#RequestBody CustomObject customObject){
...
}
If this question is about RESTful best practice, since you are developing webservice for creating an Order object, this is how I would design it
Order.java
public class Order {
private Integer code;
private String name;
public Integer getCode() {
return code;
}
public void setCode(final Integer code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
Controller
#RequestMapping(value = "/orders", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Order> createOrder(#Valid #RequestBody Order order){
...
}
Technically, you can do many things to achieve the same thing, but that will not be a RESTful service, it will be an RPC at best.

Receive URL in spring

I try doing confirmation registration from email, on the email I send this code:
String token = UUID.randomUUID().toString(); //for send email
String confirmationUrl = "<a href='" +
"http://localhost:8080/registrationConfirm.html?token="
+ token+"'>Click for end Registration</a>";
helper.setText("message", confirmationUrl.toString());
I receive something like this:
http://localhost:8080/registrationConfirm.html?token=88ab5907-6ab5-40e2-89d5-d6a7e8cea3c2
How I can receive this 88ab5907-6ab5-40e2-89d5-d6a7e8cea3c2 in spring?
I want doing a new controller, he will be check if 88ab5907-6ab5-40e2-89d5-d6a7e8cea3c2 exist in DB, then he activated registration, if no - talk about misstake.
And I do not understand how the conroller will be look, I do so
#RequestMapping(value = "/token", method = RequestMethod.POST)
public #ResponseBody
String getAttr(#PathVariable(value="token") String id,
) {
System.out.println(id);
return id;
}
To complete the comment and hint Ali Dehghani has given (have a look at the answer https://stackoverflow.com/a/17935468/265043):
#RequestMapping(value = "/registrationConfirm", method = RequestMethod.POST)
public #ResponseBody
String getAttr(#RequestParam(value="token") String id) {
System.out.println(id);
return id;
}
Note that I ignored the html suffix in the request mapping annotation. You should read the docs about (default) content negotiation starting at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-suffix-pattern-match
this another variant
#RequestMapping(value = "/registrationConfirm", method = RequestMethod.POST)
public void getMeThoseParams(HttpServletRequest request){
String goToURL = request.getParameter("token");
System.out.println(goToURL);
}

Junit Mockito with spring - test case for the Json String return

I am learning Junit Mockito to test the spring- mvc controller using Spring 3.2 in Intellij.
my controller is
#RequestMapping(value = "/user", method = RequestMethod.GET)
public String initUserSearchForm(ModelMap modelMap) {
User user = new User();
modelMap.addAttribute("User", user);
return "linkedInUser";
}
#RequestMapping(value = "/byName", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public
#ResponseBody
String getUserByName(HttpServletRequest request,#ModelAttribute("userClientObject") UserClient userClient) {
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
return getUserByName(userClient, firstName, lastName);
}
what i have done is i have one form to search the user by name. UserClient Object is a Session Attribute and i tried
to write a junit test case for my controller
#Test
public void testInitUserSearchForm() throws Exception {
this.liClient = client.createUserClient();
mockMvc.perform(get("/user"))
.andExpect(status().isOk())
.andExpect(view().name("user"))
.andExpect(forwardedUrl("/WEB-INF/pages/user.jsp"));
}
#Test
public void testGeUserByName() throws Exception {
String firstName = "Wills";
String lastName = "Smith";
mockMvc.perform(get("/user-byName"))
.andExpect(status().isOk());
}
How do I test my getUserByName method and how would i add session attribute? Please anyone can help me to
write testcase with possible tests for that method. Thanks in advance
hmmm.
You could try
mockMvc.perform(get("/user-byName").sessionAttr("userClientObject", userClientObject))
.andExpect(status().isOk());
to setup userClientObject in test fixture.
What does "return getUserByName(userClient, firstName, lastName);" exactly do? If it doesn't involve external dependence, just assert your return in andExpect(jsonPath()) clause.
I thought it should be #SessionAttribute by the way.
I use
mockMvc.perform(get("/user-byName").flashAttr("userClientObject", userClientObject)) .andExpect(status().isOk())

Resources