Mock server Request - java

Im using spring, and in my controller method im expecting a query paramether
#RequestMapping(method = RequestMethod.GET)
public MyClass myMethod(
#ApiParam(defaultValue = "some string", value = "some text") #RequestParam("myParam") MyClass2 myParam) {
//do something
}
now in JUnit test i want to call this method, for this i have prepeared a request, however i can not find a proper way to setQueryString()
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/pathToMyMethod");
request.setQueryString(new MyClass2().toString());
Constructing a new object and calling toString() on it does not work.
(calling empty constructor is creating object with random values)
Failure trace:
org.springframework.web.bind.MissingServletRequestParameterException: Required MyClass2 parameter 'myParam' is not present.
How to create such request properly?

Use MockMvc.
mockMvc.perform(get("/").param("myParam", "paramValue"))
.andExpect(status().isOk());

Related

How to pass a plain(not annotated api parameter) object with MockMvc

i am trying to pass a regular object to an api, via the MockMvc library.
Here is the example (Partiucalarly the FilterProperties properties object):
API:
#GetMapping("/test-api")
public PageResponse<SomeDto> getAllObjects(
FilterProperties properties,
#RequestParam(value = "searchPhrase", defaultValue = "") String searchPhrase,
#RequestParam(value = "actionType") ActionType actionType) {
System.out.println(searchPhrase);
return null;
}
I managed to successfully pass the #RequestParams with .param("searchPhrase", "SomePhrase"), however i cannot seem to find a way to pass the FilterProperties object, since its just a plain object and is not annotated as param, request body or some sort of attribute.
TEST:
final MvcResult mvcResult = restServiceMockMvc
.perform(get(CONTROLLER_BASE_PATH + "/test-api")
.param("searchPhrase", "SomePhrase")
.param("actionType", String.valueOf(ActionType.EDIT))
.requestAttr("properties", filterProperties)
.contentType(APPLICATION_JSON_UTF8))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
I tried with requestAttr, flashAttr, sessionAttr and it does not break the call, however the api receives an empty object for filterProperties.
I appreciate any insights!
FilterProperties will be treated as there are #ModelAttribute annotated on it (mentioned by the rules in this table).
And #ModelAttribute will enable data binding which will try to bind the value from query parameters , or field name of the form data or others (see this for more details) to FilterProperties .
So that means assuming FilterProperties has the following fields :
public class FilterProperties {
private String prop1;
private String prop2;
}
Then you can configure the MockMvc as
mockMvc.perform(get(CONTROLLER_BASE_PATH + "/test-api")
.param("searchPhrase", "SomePhrase")
.param("actionType", String.valueOf(ActionType.EDIT))
.param("prop1", "prop1-value")
.param("prop2", "prop2-value"))
in order to pass the following values to the fields of the FilterProperties :
prop1 = prop1-value
prop2 = prop2-value
whenever you pass an object to an api, it has to be part of the api signature in one way or another; i guess here you want to pass a body for the GET api(which is highly discouraged),since GET calls are idempotent by nature.
if though if its for testing try passing it as a requestbody and then mock it

How to handle multiple parameters with ObjectMapper?

I would like to know how one tests a controller (post) which requires multiple arguments.
#RequestMapping(value = PATH_TO_OBFUSCATED, method = RequestMethod.POST)
public ResponseEntity<String> download(#RequestBody String requestBody, #RequestParam("obfuscated") boolean obfiscated) {
return obfuscated.download(requestBody, obfiscated);
}
I know, when I am testing a spring mvc controller with one param, I can use ObjectMapper like so:
.content(new ObjectMapper().writeValueAsString(obfuscated))
But, how should I use the ObjectMapper when there's >=2?
As said in the comments you have just 1 body. So maybe something like this:
this.mockMvc.perform(
post("/obfuscated").
contentType(MediaType.APPLICATION_JSON).
content(json).// <-- the body
param("obfuscated", "true"))// <-- the param
.andExpect(status().isOk());

Get original mapping value inside Spring controller method

Since I'm using the CQRS pattern, I'm trying to create a single controller method that accepts every POST call with a command in its request body and send it.
I'm almost there, but I can't get the path variables.
I created a custom HandlerMapping
#Bean
public HandlerMapping requestMappingHandlerMapping() throws NoSuchMethodException {
for (final UrlEnum urlEnumItem : UrlEnum.values()) {
requestMappingHandlerMapping.registerMapping(new RequestMappingInfo(urlEnumItem.getCommandName(),
new PatternsRequestCondition(urlEnumItem.getUrl()),
null,
null,
null,
null,
null,
null),
commandController,
commandController.getClass().getDeclaredMethod("commandHandler", HttpServletRequest.class)
);
}
return requestMappingHandlerMapping;
}
and this is my controller method signature
#RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Object> commandHandler(final HttpServletRequest request) throws Exception {
// controller code here
}
If the url path is something like /api/test it works, but with something like /api/test/{idEntity} I don't have any PathVariable available in the request.
I tried everything like
String originalUrl = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
which returns the valued url (i.e. /api/test/1234), not the template, or adding
#PathVariable Map<String, Object> parameters
as a parameter in the method, which is empty.
Debugging the request object it seems there isn't anything useful to identify the path variables.
Maybe I should interrogate the HandlerMapping, but I can't have access to it in the controller method.
Is there a way to extract the pathVariables in the controller method?
It was an error in the configuration. I shouldn't have added the RequestMapping annotation to the controller method because it overrode my configuration.
Now I have
#RestController
public class CommandController extends AbstractController {
private final MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
#Override
protected ModelAndView handleRequestInternal(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
// controller code here
return new ModelAndView(mappingJackson2JsonView);
}
}

Spring Rest RequestMethod.GET returns 400 Bad Request for #RequestParam required=true when missing

I am new to Spring and Rest Endpoints.
I have a controller, which accepts #RequestParam and returns a JSON Response.
By default the #RequestParam required = "true", which is how I need it.
I am using Spring 3.1.3
This is my Get Method in the controller:
#Controller
#RequestMapping("/path")
public class MyController{
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = true) final String test) {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
When I send a get with the request param it hits the endpoint , which is how I expect.
Example : path/search/again.do?test=yes
Everything is perfect.
This is where I am having issue:
When I send a Get with that value missing:
Example: path/search/again.do
I get a 400 Bad Request. May be this is correct.
But what I want to achieve is. When the required value is missing in the GET request.
I can send a JSON response as that #RequestParam Value test is missing.
Can anybody guide me how to achieve this.
I am not sure what I am missing.
Thanks in advance.
If you look closely at your code, you'll see that the answer is staring right at you. Just change required to false and you should be good to go. When the user doesn't provide a value for GET parameter test, then you can return a special message.
#Controller
#RequestMapping("/path")
public class MyController {
#RequestMapping(value = "/search/again.do", method = RequestMethod.GET, produces = {
"application/json"
})
public ResponseEntity<?> find(#RequestParam(value = "test", required = false) final String test) {
if (test == null) {
return new ResponseEntity<String>("test parameter is missing", HttpStatus.OK);
}
else {
return new ResponseEntity<String>("Success ", HttpStatus.OK);
}
}
}
Solution 1: You can use custom #ExceptionHandler in your controller, e.g
#ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<?> paramterValidationHandler(HttpServletResquest request){
//validate the request here and return an ResponseEntity Object
}
Solution 2: Would be custom spring ErrorController which I never have tried myself but it possible to override it.
Solution 3: You can write an ControllerAdvice for a global controller exception handling.
Well if you set the parameter test is required. U just can't send the request without that param. Try to change the param required= false and handle the missing param in the method. You can us something likeif(test==null) throw new Exception("Param test missing")

Manually serializing Jersey Response

I have a resource:
#Path("/")
public class Resource {
#GET
public Response getResponse() {
//..
final GenericEntity<List<BusinessObject>> entity = new GenericEntity<List<BusinessObject>>(businessobjects) { };
return Response.status(httpResultCode).entity(entity).build();
}
}
I want to unit test this method without using a Jersey client, but I don't know how to get the body of the Response object. I can't see a method that works. Here's the test method:
#Test
public void testMethod() {
Resource resourceUnderTest = new Resource();
Response response = resourceUnderTest.getResponse();
List<BusinessObject> result = ???;
}
I can get the result I want if I go though a Jersey Client, but I would rather just call the method directly without making any HTTP requests.
List<BusinessObject> result = (List<BusinessObject>)response.getEntity();
This will return the object you pass into the entity method of response builder. The Response object doesn't serialize the result. Looking at the previous method, getEntity will probably return GenericEntity> so you'd want code like this.
GenericEntity<List<BusinessObject>> result = (GenericEntity<List<BusinessObject>>)response.getEntity();

Categories

Resources