How to check JSON response in Spring MVC test - java

I have a servlet defined in web.xml, so I defined it inside a Controller for testing only for MyResource:
#Controller
public class TestMyServlet {
MyResource servlet;
#Autowired
AutowireCapableBeanFactory beanFac;
#PostConstruct
void init() {
servlet = new MyResource();
beanFac.autowireBean(servlet);
}
#RequestMapping(value = "/servlet/api/update", method = RequestMethod.POST)
public MyResponse handle(HttpServletRequest request, HttpServletResponse response, #RequestBody String json) {
return servlet.update(json);
}
Then I test it using MockHttpServletRequestBuilder:
MockHttpServletRequestBuilder mockHttpServletRequestBuilder = MockMvcRequestBuilders
.post("/servlet/api/update")
.content("{\"id\":1,\"toggle\":true}]")
.session(httpSession)
.contentType(MediaType.APPLICATION_JSON);
MvcResult mvcResult = this.mockMvc.perform(mockHttpServletRequestBuilder)
.andDo(MockMvcResultHandlers.print())
.andReturn();
ModelAndView modelAndView = mvcResult.getModelAndView().getModelMap();
String response = mvcResult.getResponse().getContentAsString();
In servlet I don't use ModelAndView, just returning a POJO object (MyResponse) that is serialize to JSON response
I'm seeing MyResponse object as a second attribute in ModelAndView, but response is null
How can I check JSON string returned in this response?

There is one way here, i hope i understood the question correct ,
MockMvcRequestBuilders
.post("/servlet/api/update")
.content("{\"id\":1,\"toggle\":true}]")
.session(httpSession)
.contentType(MediaType.APPLICATION_JSON)
.andExpect(jsonPath("$[0].key",is("value")));
andExpect(jsonPath("$[0].key",is("value")))
you can use this for each key and value.
Or
try this ,
MockMvcRequestBuilders
.post("/servlet/api/update")
.content("{\"id\":1,\"toggle\":true}]")
.session(httpSession)
.contentType(MediaType.APPLICATION_JSON)
.andExpect(content().string(containsString("value")));

Related

Integration Testing Async controller

I am doing controller integration testing. A controller with a get mapping returns Flux.
#Slf4j
#RequiredArgsConstructor
#RequestMapping("journal")
public class EntryController {
private final SomeService someService;
#GetMapping
public Flux<MyEntity> getEntity(
#RequestParam(required = false) String documentId,
#RequestParam(required = false) String docNumber){
return someService.getEntities( GetEntriesRequest.builder()
.documentId(documentId)
.docNumber(docNumber).build;
}
#PostMapping
public MyEntity postNew(#RequestBody #Valid MyEntity entity) {
return someService.save(entity);
}
}
.
Initially, I tried to test it like this. (method asJson remakes the Entity created by creatingEntity method in a Json format). I'm already tested a controller with a post mapping and it works right.
#Test
void getEntriesByDocumentNumber() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(post("/journal")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(asJson(creatingEntity())))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andReturn();
String response = mvcResult.getResponse().getContentAsString();
String documentIdFromResponse =
JsonPath.parse(response).read("$.documentId");
this.mockMvc.perform(get("/journal")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.param("documentId", documentIdFromResponse))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk());
I do not know how to process the response that I receive. The fact is that the response body is empty, but the method works, this can be seen in the async result. I did not find how to get the asinc result. And I can’t use JsonPath, because the body is empty.
HTTP Method = GET
Request URI = /journal
Parameters = {documentId=[1590067372983-9ce4f563-520d-42ff-bd31-5b78befaf4b1]}
Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json"]
Body = null
Session Attrs = {}
Async:
Async started = true
Async result = [MyEntity(documentId=1590067372983-9ce4f563-520d-42ff-bd31-5b78befaf4b1, documentNumber=100)]
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
I try to use WebTestClient, But this code does not work. It's falling with No bean named 'webHandler' available
#SpringBootTest
#AutoConfigureMockMvc
class ApplicationTests {
#Autowired
private MockMvc mockMvc;
WebTestClient webTestClient;
#BeforeEach
void setUp(ApplicationContext context) {
webTestClient = WebTestClient.bindToApplicationContext(context).build();
}
#Test
void getEntityTest() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(post("/journal")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(asJson(creatingEntity())))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andReturn();
String response = mvcResult.getResponse().getContentAsString();
String documentIdFromResponse = JsonPath.parse(response).read("$.documentId");
webTestClient.get()
.uri("journal/")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$[0].documentId").isEqualTo(documentIdFromResponse);
}
}
I'm already find this. But I don't know how to use it
#Bean
public WebHandler webHandler() {
//implement your bean initialization here
}

Getting httpServletRequest attribute with MockMvc

I have a really simple controller defined in this way:
#RequestMapping(value = "/api/test", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody Object getObject(HttpServletRequest req, HttpServletResponse res) {
Object userId = req.getAttribute("userId");
if (userId == null){
res.setStatus(HttpStatus.BAD_REQUEST.value());
}
[....]
}
I tried to call using MockMvc in many different way but, I'm not able to provide the attribute "userId".
For instance, with this it doesn't work:
MockHttpSession mockHttpSession = new MockHttpSession();
mockHttpSession.setAttribute("userId", "TESTUSER");
mockMvc.perform(get("/api/test").session(mockHttpSession)).andExpect(status().is(200)).andReturn();
I also tried this, but without success:
MvcResult result = mockMvc.perform(get("/api/test").with(new RequestPostProcessor() {
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.setParameter("userId", "testUserId");
request.setRemoteUser("TESTUSER");
return request;
}
})).andExpect(status().is(200)).andReturn();
In this case, I can set the RemoteUser but never the Attributes map on HttpServletRequest.
Any clue?
You add a request attribute by calling requestAttr ^^
mockMvc.perform(get("/api/test").requestAttr("userId", "testUserId")...
You could use
mvc.perform(post("/api/v1/...")
.with(request -> {
request.addHeader(HEADER_USERNAME_KEY, approver);
request.setAttribute("attrName", "attrValue");
return request;
})
.contentType(MediaType.APPLICATION_JSON)...
#ResponseStatus(HttpStatus.OK)
#GetMapping(Routes.VALIDATE_EMAIL_TOKEN + "/validate")
public String validateEmailToken(#RequestParam(value = "token") String token,
HttpServletRequest httpServletRequest) throws RestServiceException {
return credentionChangeService.getUserByToken(token, httpServletRequest);
}
//test method
#Mock
private HttpServletRequest httpServletRequest
#Mock
private MerchantCredentialsChangeService mockCredentionChangeService;
#Test
public void testValidateEmailToken() throws Exception {
final String token = "akfkldakkadjfiafkakflkd";
final String expectedUsername = "9841414141";
Mockito.when(mockCredentionChangeService.getUserByToken(Matchers.eq(token), Matchers.any(HttpServletRequest.class)))
.thenReturn(expectedUsername);
mockMvc.perform(get(Routes.VALIDATE_EMAIL_TOKEN + "/validate")
.param("token", token))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().string(expectedUsername));
}

How to specify #RequestMapping params in MockMvc

I have a controller:
#Controller
#RequestMapping(value = "/bookForm")
public class BookFormController {
#Autowired
private BookHttpRequestParser parser;
#Autowired
private BooksService booksService;
#RequestMapping(params = "add", method = RequestMethod.POST)
public String addBook(HttpServletRequest request) {
try {
Book newBook = parser.createBookFromRequest(request);
booksService.addBook(newBook);
} catch (InvalidTypedParametersException e) {
}
return "redirect:index.html";
}
This Controller has a method for adding book to DB. Method has #RequestMapping annotation with params = "add" value.
Im trying to set this params criteria to controller unit test method:
#Test
public void addBook() throws Exception{
HttpServletRequest request = mock(HttpServletRequest.class);
Book book = new Book();
when(parser.createBookFromRequest(request)).thenReturn(book);
mockMvc.perform(post("/bookForm", "add"))
.andExpect(status().isOk())
.andExpect(view().name("redirect:index.html"));
}
Where to specify this #ResuetsMapping params value?
This:
mockMvc.perform(post("/bookForm", "add"))
doesn't work at all.
The following should work.
mockMvc.perform(post("/bookForm?add="))
use RequestBuilder requestBuilders;
object to build your request
requestBuilders = MockMvcRequestBuilders.get("URL/{Pathvariable}","PathvariableValue")
.contentType(MediaType.APPLICATION_JSON)
.header("HeaderName", HeaderValue)
.param("ParameterName", "Value")
.param("ParameterName", "Value")
.accept(MediaType.APPLICATION_JSON);
and the perfrom
mockMvc.perform(requestBuilders)
.andDo(print())
.andExpect(status().isOk())
.andReturn();

EasyMock Controller Mapping and Status Code Tests

I'm trying to test my controller mapping and the response http status codes. Therefore I'm using the RequestMappingHandlerAdapter and the RequestMappingHandlerMapping.
My Controller
#Controller
#RequestMapping(value ="/user")
public class AdminSpringController {
#Autowired
public UserAdminService userService;
private final Logger log = LoggerFactory.getLogger(AdminSpringController.class);
#RequestMapping(method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
#ResponseStatus(HttpStatus.OK)
public List<User> getUsers() {
log.trace("Request to get all users.");
return userService.getUsers();
}
}
and my Test class:
public class AdminSpringControllerTests {
AdminSpringController cut;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private RequestMappingHandlerAdapter adapter;
private RequestMappingHandlerMapping handlerMapping;
#Test
public void testGetSc() throws Exception{
adapter = new RequestMappingHandlerAdapter();
handlerMapping = new RequestMappingHandlerMapping();
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setRequestURI("/user");
request.addHeader("Accept", "application/json");
MockHttpServletResponse response = new MockHttpServletResponse();
Object handler = handlerMapping.getHandler(request).getHandler();
ModelAndView mav = adapter.handle(request, response, handler);
assertNotNull(mav);
}
}
But I'm getting an NullPointerException in the row Object handler = ...
I simply want to test my mapping and then check the HTTP status codes from my response. Is this the right approach or is my test implementation totally wrong. For the tests I need to use EasyMock. As next step I wanted to test if the response status codes (response.getStatus()) is equals to SC_OK (200).
Thx for any help :)
I am using SpringMvc Test approach, mixed with EasyMock, which is a good approach.
#ContextConfiguration("ProjectFacadeTest-context.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class AdminSpringControllerTests {
...
private MockMvc mockMvc;
...
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(imageController).build();
}
EasyMock.expect(mockPersistedProjectService.getImages(EasyMock.anyLong())).andReturn(images);
EasyMock.replay(mockPersistedProjectService);
MvcResult result =
this.mockMvc.perform(get("/resources/projects/1000/images")).andExpect(content().type("application/json"))
.andExpect(status().isOk()).andReturn();
MockHttpServletResponse response = result.getResponse();
//VERIFY RESPONSE
EasyMock.verify(mockPersistedProjectService);
XML FILE
<bean id="mockArtifactService" class="org.easymock.EasyMock"
factory-method="createStrictMock" primary="true">
<constructor-arg value="com.xxxxxx.service.ArtifactService" />
</bean>

Spring controller get request/response

How do I get the request/response that I can setcookie? Additionally, at the end of this method, how can I can redirect to another page?
#RequestMapping(value = "/dosomething", method = RequestMethod.GET)
public RETURNREDIRECTOBJ dosomething() throws IOException {
....
return returnredirectpagejsp;
}
How about this:
#RequestMapping(value = "/dosomething", method = RequestMethod.GET)
public ModelAndView dosomething(HttpServletRequest request, HttpServletResponse response) throws IOException {
// setup your Cookie here
response.setCookie(cookie)
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/other-page");
return mav;
}
Just pass it as argument: public String doSomething(HttpServletRequest request). You can pass both the request and response, or each of them individually.
return the String "redirect:/viewname" (most often without the .jsp suffix)
For both questions, check the documentation, section "15.3.2.3 Supported handler method arguments and return types"
You can also simply #Autowire. For example:
#Autowired
private HttpServletRequest request;
Though HttpServletRequest is request-scoped bean, it does not require your controller to be request scoped, as for HttpServletRequest Spring will generate a proxy HttpServletRequest which is aware how to get the actual instance of request.
You could also use this way
#RequestMapping(value = "/url", method = RequestMethod.GET)
public String method(HttpServletRequest request, HttpServletResponse response){
Cookie newCookie = new Cookie("key", "value");
response.addCookie(newCookie);
return "redirect:/newurl";
}

Categories