web-dev-qa-db-fra.com

Comment envoyer un objet fictif au format JSON dans mockmvc

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?

13
Sourabh

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());
}
23
matsev

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.

7
Serge Ballesta

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();
1
Sourabh

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();
1
virtual agent 07

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>
0
exe_sys