Je souhaite envoyer un objet fictif dans le contrôleur via MockMvc avec le type de contenu JSON. Mais quand j'essaye de sérialiser la maquette, l'erreur est la suivante:
Java.lang.UnsupportedOperationException: Expecting parameterized type, got interface org.mockito.internal.MockitoInvocationHandler.
Are you missing the use of TypeToken idiom?
Mon code est le suivant:
@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());
}
Quelqu'un peut-il me dire ce que je manque?
Je vous propose de créer un stub de votre SomeClass
qui renvoie les valeurs connues pour les méthodes getProperty1()
et getProperty2()
. En fonction de la manière dont SomeClass
est implémenté, vous pouvez soit créer une instance new
directement, sous-classe et remplacer certaines méthodes, créer une classe interne anonyme s'il s'agit d'une interface, etc.
@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());
}
Même si cela était possible, la soumission d'un objet fictif à un convertisseur JSON supposerait un test unitaire dédié à cette opération: l'objet fictif peut avoir de nombreux attributs et méthodes bien au-delà de la classe réelle et la sérialisation peut conduire à un vraiment étrange résultat.
IMHO, comme c'est un test unitaire, vous devriez écrire à la main la chaîne sérialisée json. Et vous pouvez faire d’autres tests si vous devez contrôler comment Gson procède à la sérialisation.
J'ai trouvé un moyen de sérialiser un objet fantaisie de la manière suivante:
Gson gson = new GSon();
String json = gson.toJson(mockedObject, mockedObjectType.class);
Bien que ce que j’essayais soit INUTILE puisque json sera débarrassé de toutes les moqueries que j’ai fournies à la fonction test (), de ce fait, lorsque l’objet sera reconstruit, il n’a aucune valeur de se moquer de lui et jette NullPointerException à la première exemple d'utilisation d'une fonction/propriété.
EDIT: Si vous voulez sérialiser les valeurs NULL, il existe une fonction pour cela aussi:
Gson gson = new GsonBuilder().serializeNulls().create();
Nous avions un problème similaire: Il y avait une instruction de journalisation pour la sortie d’un objet sérialisé vers json. Et le cas de test unitaire pour cette erreur produite parce que gson ne pouvait pas sérialiser l'objet fictif . Il a été résolu en fournissant une stratégie d'exclusion qui ignore la sérialisation de la classe et des champs de type classe:
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();
Dans la configuration de test, vous pouvez encapsuler le convertisseur de message par défaut avec un autre convertisseur de message prenant en charge la sérialisation de tout objet dans 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());
}
}
}
Dans le contexte XML de Spring, mettez:
<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>