Как отправить макет объекта как JSON в mockmvc
Я хочу отправить макет объекта в контроллер через MockMvc с типом контента JSON. Но когда я пытаюсь сериализовать макет, ошибка:
java.lang.UnsupportedOperationException: Expecting parameterized type, got interface org.mockito.internal.MockitoInvocationHandler.
Are you missing the use of TypeToken idiom?
Мой код выглядит следующим образом:
@Test
public void testSomething(){
String xyz = "";
Integer i = 10;
SomeClass inst = mock(SomeClass.class, withSettings().serializable());
when(inst.getProperty1()).then(xyz);
when(inst.getProperty2()).then(i);
Gson gson = new Gson();
String json = gson.toJson(inst); // this is creating error
this.mockmvc.perform(put("/someUrl/").contentType(MediaType.JSON).content(json)).andExpect(status().isOk());
}
Может ли кто-нибудь сказать мне, что мне не хватает?
Ответы
Ответ 1
Я предлагаю вам создать заглушку вашего SomeClass
которая возвращает известные значения метода getProperty1()
и getProperty2()
. В зависимости от того, как реализован SomeClass
, вы можете либо создать new
экземпляр этого объекта, либо подкласса, либо переопределить некоторые методы, создать анонимный внутренний класс, если это интерфейс и т.д.
@Test
public void testSomething(){
String xyz = "";
Integer i = 10;
// alt 1:
SomeClass stub = new SomeClass(xyz, i);
// alt 2:
SomeClass stub = new StubSomeClass(xyz, i); // StubSomeClass extends SomeClass
// alt 3:
SomeClass stub = new SomeClass() {
@Override
String getProperty1() {
return xyz;
}
@Override
Integer getProperty2() {
return i;
}
}
Gson gson = new Gson();
String json = gson.toJson(stub);
this.mockmvc.perform(put("/someUrl/")
.contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isOk());
}
Ответ 2
Даже если бы это было возможно, отправка имитационного объекта в JSON-конвертер предполагала бы единичный тест, посвященный этой операции: у mock-объекта может быть много атрибутов и методов, находящихся далеко за пределами реального класса, и сериализация может привести к действительно странному результату.
ИМХО, поскольку это единичный тест, вы должны написать вручную серию сериалов json. И вы можете делать другие тесты, если вам нужно контролировать, как Gson выполняет сериализацию
Ответ 3
Я нашел способ сериализации макетного объекта следующим образом:
Gson gson = new GSon();
String json = gson.toJson(mockedObject, mockedObjectType.class);
Хотя то, что я пытался, было случайным, поскольку json будет лишен всех насмешек, которые я предоставил в функции test(), тем самым, когда объект будет перестроен, он не будет иметь никакого значения насмехаться над ним и будет бросать NullPointerException на первом экземпляр использования любой функции/свойства.
EDIT: Если вы хотите сериализовать нули, для этого есть функция:
Gson gson = new GsonBuilder().serializeNulls().create();
Ответ 4
У нас была аналогичная проблема: для вывода объекта, сериализованного в json, был оператор ведения журнала. И единичный тестовый пример для этой ошибки, потому что gson не смог сериализовать макет объекта. Он был решен с помощью стратегии исключения, которая пропускает сериализацию класса и полей типа Class:
private final Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return clazz instanceof Class;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
return field.getDeclaredClass() == Class.class;
}
}).create();
Ответ 5
В тестовой конфигурации вы можете конвертировать конвертер сообщений по умолчанию в другой конвертер сообщений, который поддерживает сериализацию любого объекта в String.
package com.example;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.util.Arrays;
public class MockObjectHttpMessageConverter extends AbstractHttpMessageConverter {
private final AbstractHttpMessageConverter primaryConverter;
public MockObjectHttpMessageConverter(AbstractHttpMessageConverter primaryConverter) {
this.primaryConverter = primaryConverter;
setSupportedMediaTypes(Arrays.asList(MediaType.ALL));
}
@Override
protected boolean supports(Class clazz) {
return true;
}
@Override
protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
throw new UnsupportedOperationException();
}
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
try {
primaryConverter.write(o, MediaType.ALL, outputMessage);
} catch (Exception e) {
IOUtils.write(o.toString(), outputMessage.getBody());
}
}
}
В контексте Spring XML:
<mvc:message-converters>
<bean class="com.example.MockObjectHttpMessageConverter">
<constructor-arg>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter">
<property name="gson">
<bean class="com.google.gson.Gson" factory-bean="gsonBuilder" factory-method="create"/>
</property>
</bean>
</constructor-arg>
</bean>
</mvc:message-converters>