使用 Spring MockMVC 时如何从 JSON 响应中提取值
How to extract value from JSON response when using Spring MockMVC
我有一个接受 POST 请求的端点。我想从 JSON 响应中获取新创建的实体的 ID。
下面是我尝试执行此操作的代码段。
mockMvc.perform(post("/api/tracker/jobs/work")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(workRequest)))
.andExpect(status().isCreated());
如果我得到该 ID,我将在数据库中查询新创建的实体并执行如下断言:
Work work = work service.findWorkById(id);
assertThat(work.getJobItem().getJobItemName()).isEqualTo(workRequest.getJobItem().getJobItemName());
assertThat(work.getJobItem().getQuantities()).hasSize(workRequest.getQuantities().size());
assertThat(work.getJobItem().getQuantityPools()).hasSize(workRequest.getQuantities().size());
我已经设法使用 Spring MockMVC 结果处理程序解决了我的问题。我创建了一个测试实用程序来将 JSON 字符串转换回对象,这样我就可以获取 ID。
转换实用程序:
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);
}
单元测试:
@Test
@Transactional
public 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());
}
从 JSON 响应中检索任意通用值的一种方法是利用 MockMVC 库中的 jsonPath() 匹配器,并将其与自定义匹配器结合使用,该匹配器捕获要求匹配的所有值.
首先,自定义匹配器:
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);
}
}
现在,使用自定义匹配器捕获值并使用 jsonPath() 匹配器识别应捕获的内容:
@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)));
}
您可以简单地在结果对象上使用 JsonPath.read
:
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);
...
我有一个接受 POST 请求的端点。我想从 JSON 响应中获取新创建的实体的 ID。
下面是我尝试执行此操作的代码段。
mockMvc.perform(post("/api/tracker/jobs/work")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(workRequest)))
.andExpect(status().isCreated());
如果我得到该 ID,我将在数据库中查询新创建的实体并执行如下断言:
Work work = work service.findWorkById(id);
assertThat(work.getJobItem().getJobItemName()).isEqualTo(workRequest.getJobItem().getJobItemName());
assertThat(work.getJobItem().getQuantities()).hasSize(workRequest.getQuantities().size());
assertThat(work.getJobItem().getQuantityPools()).hasSize(workRequest.getQuantities().size());
我已经设法使用 Spring MockMVC 结果处理程序解决了我的问题。我创建了一个测试实用程序来将 JSON 字符串转换回对象,这样我就可以获取 ID。
转换实用程序:
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);
}
单元测试:
@Test
@Transactional
public 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());
}
从 JSON 响应中检索任意通用值的一种方法是利用 MockMVC 库中的 jsonPath() 匹配器,并将其与自定义匹配器结合使用,该匹配器捕获要求匹配的所有值.
首先,自定义匹配器:
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);
}
}
现在,使用自定义匹配器捕获值并使用 jsonPath() 匹配器识别应捕获的内容:
@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)));
}
您可以简单地在结果对象上使用 JsonPath.read
:
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);
...