How to extract value from JSON response when using Spring MockMVC How to extract value from JSON response when using Spring MockMVC spring spring

How to extract value from JSON response when using Spring MockMVC


You can simply use JsonPath.read on the result object:

MvcResult result = mockMvc.perform(post("/api/tracker/jobs/work")    .contentType(TestUtil.APPLICATION_JSON_UTF8)    .content(TestUtil.convertObjectToJsonBytes(workRequest)))    .andExpect(status().isCreated())    .andReturn();    String id = JsonPath.read(result.getResponse().getContentAsString(), "$.id")Work work = workService.findWorkById(id);...


I have managed to solve my problem using Spring MockMVC result handler. I created a testing utility to convert the JSON string back to an object and so allowing me to get the ID.

Conversion Utility:

 public static <T>  Object convertJSONStringToObject(String json, Class<T> objectClass) throws IOException {    ObjectMapper mapper = new ObjectMapper();    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);    JavaTimeModule module = new JavaTimeModule();    mapper.registerModule(module);    return mapper.readValue(json, objectClass);}

Unit Test:

 @Test@Transactionalpublic void createNewWorkWorkWhenCreatedJobItemAndQuantitiesPoolShouldBeCreated() throws Exception {    mockMvc.perform(post("/api/tracker/jobs/work")        .contentType(TestUtil.APPLICATION_JSON_UTF8)        .content(TestUtil.convertObjectToJsonBytes(workRequest)))        .andExpect(status().isCreated())        .andDo(mvcResult -> {            String json = mvcResult.getResponse().getContentAsString();            workRequestResponse = (WorkRequestResponse) TestUtil.convertJSONStringToObject(json, WorkRequestResponse.class);        });    Work work = workService.findWorkById(workRequestResponse.getWorkId());    assertThat(work.getJobItem().getJobItemName()).isEqualTo(workRequest.getJobItem().getJobItemName());    assertThat(work.getJobItem().getQuantities()).hasSize(workRequest.getQuantities().size());    assertThat(work.getJobItem().getQuantityPools()).hasSize(workRequest.getQuantities().size());}


One way to retrieve an arbitrary, generic value from the JSON response is to leverage the jsonPath() matcher from the MockMVC library and couple it with a custom matcher that captures all values it is asked to match.

First, the custom matcher:

import org.hamcrest.BaseMatcher;/** * Matcher which always returns true, and at the same time, captures the * actual values passed in for matching. These can later be retrieved with a * call to {@link #getLastMatched()} or {@link #getAllMatched()}. */public static class CapturingMatcher extends BaseMatcher<Object> {    private List<Object> matchedList = new ArrayList<>();    @Override    public boolean matches(Object matched) {        matchedList.add(matched);        return true;    }    @Override    public void describeTo(Description description) {        description.appendText("any object");    }    /**     * The last value matched.     */    public Object getLastMatched() {        return matchedList.get(matchedList.size() - 1);    }    /**     * All the values matched, in the order they were requested for     * matching.     */    public List<Object> getAllMatched() {        return Collections.unmodifiableList(matchedList);    }}

Now, use the custom matcher to capture values and use the jsonPath() matcher to identify what should be captured:

@Test@WithMockUser(username = "reviewer", authorities = {ROLE_USER})public void testGetRemediationAction() throws Exception {    CapturingMatcher capturingMatcher = new CapturingMatcher();    // First request a list of all the available actions    mvc.perform(get("/api/remediation/action").accept(VERSION_1_JSON))            .andExpect(status().isOk())            .andExpect(jsonPath("$.content[*].remediations[*].id", hasSize(12)))            .andExpect(jsonPath("$.content[*].remediations[*].id", capturingMatcher));    // Grab an ID from one of the available actions    Object idArray = capturingMatcher.getLastMatched();    assertThat(idArray).isInstanceOf(JSONArray.class);    JSONArray jsonIdArray = (JSONArray) idArray;    String randomId = (String) jsonIdArray.get(new Random().nextInt(12));    // Now retrieve the chosen action    mvc.perform(get("/api/remediation/action/" + randomId).accept(VERSION_1_JSON))            .andExpect(status().isOk())            .andExpect(jsonPath("$.id", is(randomId)));}