Как получить исключение JsonProcessingException с помощью Jackson

Возможно, это странный вопрос, но я хотел бы получить немного больше информации о моих тестах, и хотя я закодирован против JsonProcessingException, я не могу создать полезную нагрузку, которая генерирует это исключение, возможно, потому, что Джексон довольно умный и преобразует все в строку, и даже для плохих строк это касается спецификаций JSON. Моя проблема в том, что Джексон неплохо:)

В основном я хочу получить полезную нагрузку, которая, когда я запускаю это, разбивается на JsonProcessingException:

String jsonPayload = objectMapper.writeValueAsString(payload);

Я пробовал некоторые вроде:

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

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

Я не суетился с типом, поэтому не стесняйтесь предлагать еще один. Например, пустой объект, бросает JsonMappingException, и я уже поймаю его.

Ответ 1

Вы можете использовать что-то вроде этого:

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

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

В результате получается JsonProcessingException с сообщением Direct self-reference leading to cycle (through reference chain: ClassThatJacksonCannotSerialize["self"])

Ответ 2

Я хотел сделать то же самое, и в конце концов достиг этого, используя "шпионскую" функцию Mockito, которая оборачивает реальный объект фиктивным объектом. Все вызовы фиктивного объекта перенаправляются на реальный объект, кроме тех, которые вы пытаетесь имитировать. Например:

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

Все использования om будут обрабатываться базовым экземпляром ErrorObject до тех пор, пока не будет передан экземпляр ErrorObject, после чего будет JsonProcessingException.

Новое JsonProcessingException создается как анонимный класс, так как это защищенный класс, и может быть создан только подкласс.

Ответ 3

следуя @Mike.Mathieson ответ

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

обратите внимание, что этот тест не будет работать, если ObjectMapper настроен на отключение SerializationFeature.FAIL_ON_EMPTY_BEANS, например

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

Ответ 4

Для меня, если класс не имеет общедоступных полей/методов writeValueAsString будет вызывать исключение JsonMappingException (для класса не найден сериализатор)

private static class ClassThatJacksonCannotSerialize {}

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

Ответ 5

Создание ответа Лиама, издевательствование метода toString() с циклом также заставляет Джексона сломаться.

@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: Это проще, чем это. Mockito mock всегда будет бросать его. o.o;;

Ответ 6

Попытка смоделировать с использованием mock(ObjectMapper.class) неизменно приведет к тому, что проверенное исключение недопустимо для этого метода! так как невозможно выбросить проверенное исключение (JsonProcessingException расширяет IOException). Создание самообращающегося объекта значения, как и другие предложенные ответы, может быть слишком сложным для многих случаев и выглядит как хак.

Самый простой способ, который я нашел, - это расширить ObjectMapper, а затем использовать его в своем методе тестирования. Вы должны передать подкласс в 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);
}

Ответ 7

на всякий случай это может кому-то помочь, когда я проходил модульное тестирование для JsonProcessingException, я продолжал получать эту ошибку:

JsonProcessingException has protected access in com.fasterxml.jackson...

это был мой код

// error is on the below line
JsonProcessingException e = new JsonProcessingException("borked");

doThrow(e).when(classMock).methodToMock(any(), any());

я узнал, что мне просто нужно добавить "{}" как таковой

JsonProcessingException e = new JsonProcessingException("borked") {};