Есть ли метод, построенный в Spring MockMVC для получения содержимого json как объекта?

В моем проекте Spring я создал несколько тестов, которые проверяют контроллеры / http-api. Есть ли способ получить json-содержимое ответа как десериализованный объект?

В другом проекте я использовал методы «будьте уверены» и там методы для получения результатов напрямую, как ожидаемые объекты.

Вот пример:

    MvcResult result = rest.perform( get( "/api/byUser" ).param( "userName","test_user" ) )

            .andExpect( status().is( HttpStatus.OK.value() ) ).andReturn();
    String string = result.getResponse().getContentAsString();

Метод возвращает определенный тип как json. как преобразовать этот json обратно в объект для проверки его содержимого? Я знаю способы с Джексоном или с уверенностью, но есть ли способ в spring / test / mockmvc

Нравится getContentAs(Class)

когда вы вызываете свой rets api, spring автоматически преобразует его в Object. вы можете указать, в какой объект он должен преобразовать при вызове. Ничего не могу сказать без каких-либо фрагментов кода,

pvpkiran 16.08.2018 11:21

добавлен пример кода.

dermoritz 16.08.2018 11:29
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
21
2
14 060
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Насколько я знаю, MockHttpServletResponse (в отличие от RestTemplate) не имеет метода, который мог бы преобразовать возвращенный json в определенный тип
Итак, что вы могли бы сделать, это использовать Jakson ObjectMapper для преобразования строки json в определенный тип

Что-то вроде этого

String json = rt.getResponse().getContentAsString();
SomeClass someClass = new ObjectMapper().readValue(json, SomeClass.class);

Это даст вам больше контроля, чтобы вы могли утверждать разные вещи.

Сказав это, MockMvc::perform возвращает ResultActions, у которого есть метод andExpect, который принимает ResultMatcher. У этого есть много вариантов для тестирования полученного json без преобразования его в объект.

Например

mvc.perform(  .....
                ......
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.firstname").value("john"))
                .andExpect(jsonPath("$.lastname").value("doe"))
                .andReturn();

Хотя это работает, создается новый экземпляр ObjectMapper, который может отличаться от настроенного. Вам, вероятно, лучше ввести созданный Spring Boot.

M. Deinum 16.08.2018 13:58

@Deinum, да, ты прав. но это всего лишь пример, который я показал. это до ОП, как он хочет делать. Тем не менее, спасибо за вклад.

pvpkiran 16.08.2018 14:06

Это может быть полезно:

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.togondo.config.database.MappingConfig;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Getter
public class CustomResponseHandler<T> implements ResultHandler {

private final Class<? extends Collection> collectionClass;
private T responseObject;
private String responseData;
private final Class<T> type;
private Map<String, String> headers;
private String contentType;

public CustomResponseHandler() {
    this.type = null;
    this.collectionClass = null;
}

public CustomResponseHandler(Class type) {
    this.type = type;
    this.collectionClass = null;
}

public CustomResponseHandler(Class type, Class<? extends Collection> collectionClass) {
    this.type = type;
    this.collectionClass = collectionClass;
}


protected <T> T responseToObject(MockHttpServletResponse response, Class<T> type) throws IOException {
    String json = getResponseAsContentsAsString(response);
    if (org.apache.commons.lang3.StringUtils.isEmpty(json)) {
        return null;
    }
    return MappingConfig.getObjectMapper().readValue(json, type);
}

protected <T> T responseToObjectCollection(MockHttpServletResponse response, Class<? extends Collection> collectionType, Class<T> collectionContents) throws IOException {
    String json = getResponseAsContentsAsString(response);
    if (org.apache.commons.lang3.StringUtils.isEmpty(json)) {
        return null;
    }
    ObjectMapper mapper = MappingConfig.getObjectMapper();
    JavaType type = mapper.getTypeFactory().constructCollectionType(collectionType, collectionContents);
    return mapper.readValue(json, type);
}


protected String getResponseAsContentsAsString(MockHttpServletResponse response) throws IOException {
    String content = "";
    BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(response.getContentAsByteArray())));
    String line;
    while ((line = br.readLine()) != null)
        content += line;
    br.close();

    return content;
}

@Override
public void handle(MvcResult result) throws Exception {
    if ( type != null ) {
        if (collectionClass != null) {
            responseObject = responseToObjectCollection(result.getResponse(), collectionClass, type);
        } else {
            responseObject = responseToObject(result.getResponse(), type);
        }
    }
    else {
        responseData = getResponseAsContentsAsString(result.getResponse());
    }

    headers = getHeaders(result);
    contentType = result.getResponse().getContentType();

    if (result.getResolvedException() != null) {
        log.error("Exception: {}", result.getResponse().getErrorMessage());
        log.error("Error: {}", result.getResolvedException());
    }
}

private Map<String, String> getHeaders(MvcResult result) {
    Map<String, String> headers = new HashMap<>();
    result.getResponse().getHeaderNames().forEach(
            header -> headers.put(header, result.getResponse().getHeader(header))
    );
    return headers;
}

public String getHeader(String headerName) {
    return headers.get(headerName);
}

public String getContentType() {
    return contentType;
}

}

А затем используйте его в своих тестах следующим образом:

CustomResponseHandler<MyObject> responseHandler = new CustomResponseHandler(MyObject.class);

mockMvc.perform(MockMvcRequestBuilders.get("/api/yourmom"))
            .andDo(responseHandler)
            .andExpect(status().isOk());


MyObject myObject = responseHandler.getResponseObject();

Или, если вы хотите получить коллекции:

CustomResponseHandler<Set<MyObject>> responseHandler = new CustomResponseHandler(MyObject.class, Set.class);
.
.
.
Set<MyObject> myObjectSet = responseHandler.getResponseObject();

Другие вопросы по теме