web-dev-qa-db-fra.com

Comment obtenir une exception JsonProcessingException avec Jackson

C'est peut-être une question étrange, mais j'aimerais en fait obtenir une couverture un peu plus longue sur mes tests et bien que j'ai codé avec une variable JsonProcessingException, je ne peux pas créer de charge utile générant cette exception, peut-être parce que Jackson est assez intelligent et convertit tout en chaîne. , et même pour les mauvaises chaînes, il tourne autour des spécifications JSON. Mon problème est que Jackson est très bon :)

En gros, je veux une charge utile qui, quand je lance ceci, rompt avec JsonProcessingException:

String jsonPayload = objectMapper.writeValueAsString(payload);

J'ai essayé certains comme:

HashMap<String, String> invalidJSONPayload= new HashMap<>();

invalidJSONPayload.put("021",021);
invalidJSONPayload.put("---",021);
invalidJSONPayload.put("~",021);

Je ne suis pas gêné par le type, alors n'hésitez pas à en suggérer un autre. Un objet vide, par exemple, jette JsonMappingException et j'attrape déjà celui-ci également.

16
bitoiu

Je voulais faire la même chose et finalement y arriver en utilisant la fonction "espion" de Mockito, qui enveloppe un objet réel avec un objet fictif. Tous les appels à l'objet simulé sont transférés à l'objet réel, à l'exception de ceux que vous essayez de simuler. Par exemple:

ObjectMapper om = Mockito.spy(new ObjectMapper());
Mockito.when( om.writeValueAsString(ErrorObject.class)).thenThrow(new JsonProcessingException("") {});

Toutes les utilisations de om seront gérées par l'instance ObjectMapper sous-jacente jusqu'à ce qu'une instance de ErrorObject soit transmise, auquel moment la JsonProcessingException sera levée.

NewJsonProcessingException est créé en tant que classe anonyme, car il s'agit d'une classe protégée et seule une sous-classe peut être instanciée.

9
Lee Passey

Vous pouvez utiliser quelque chose comme ceci:

private static class ClassThatJacksonCannotSerialize {
    private final ClassThatJacksonCannotSerialize self = this;

    @Override
    public String toString() {
        return self.getClass().getName();
   }
}

Ce qui donne une JsonProcessingException avec le message Direct self-reference leading to cycle (through reference chain: ClassThatJacksonCannotSerialize["self"])

7
Liam Williams

Pour moi, si une classe n'a pas de champs/méthodes publics, writeValueAsString lève une exception JsonMappingException (aucun sérialiseur n'a été trouvé pour la classe ...)

private static class ClassThatJacksonCannotSerialize {}

private void forceProcessingException() {
    ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
}
5
Mike Mathieson

S'appuyant sur la réponse de Liam, se moquer de la méthode toString() avec un cycle provoque également la rupture de Jackson.

@Test
public void forceJsonParseException() {
    try {
        Object mockItem = mock(Object.class);
        when(mockItem.toString()).thenReturn(mockItem.getClass().getName());
        new ObjectMapper().writeValueAsString(mockItem);
        fail("did not throw JsonProcessingException");
    } catch (JsonProcessingException e) {
        //pass
    }
}

EDIT: C'est beaucoup plus facile que ça. Un simulacre de Mockito le jettera toujours. o.o ;;

3
Hazel Troost

suite à @ Mike.Mathieson répondre

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

public class JacksonTest {

    @Test(expected = JsonProcessingException.class)
    // actually throws an InvalidDefinitionException (which extends JsonProcessingException)
    public void encodeThrowsException() throws JsonProcessingException {
        new ObjectMapper().writeValueAsString(new Object());
    }
}

https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/exc/InvalidDefinitionException.html

notez que ce test ne fonctionnera pas si ObjectMapper a été configuré pour désactiver SerializationFeature.FAIL_ON_EMPTY_BEANS, par exemple.

new ObjectMapper()
    .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
    .writeValueAsString(new Object());
3
Julien

Essayer de simuler avec mock(ObjectMapper.class) entraînera invariablement/ L'exception Checked n'est pas valide pour cette méthode! car il n’est pas possible de lancer une exception vérifiée (JsonProcessingException extend IOException). Créer un objet de valeur à référence automatique comme les autres réponses suggérées pourrait être trop compliqué dans de nombreux cas et ressembler à un hack.

Le moyen le plus simple que j'ai trouvé est d'étendre la variable ObjectMapper, puis de l'utiliser dans votre méthode de test. Vous devriez passer la sous-classe à SUT

@Test
public void buildJsonSwallowsJsonProcessingException() {

    class MyObjectMapper extends ObjectMapper {
        @Override
        public String writeValueAsString(Object value)
                throws com.fasterxml.jackson.core.JsonProcessingException {
            throw new com.fasterxml.jackson.core.JsonProcessingException("Forced error") {};
        }
    }

    ObjectMapper objectMapper = new MyObjectMapper();

    SUTBean sutbean = new SUTBean(objectMapper);

    sutbean.testMethod();

    assertTrue(expected, actual);
}
1
senseiwu