Как проверять разные наборы полей одного класса при десериализации JSON в тестах
Что проверяют
Понимаете ли вы, как Jackson ведёт себя с отсутствующими, лишними и null-полями, и умеете ли проверить это без десятка одинаковых тестов. Следом спрашивают, чем отсутствие поля отличается от "age": null и как это различить в модели.
Как отвечать
Каркас: один параметризованный тест, много наборов входных данных.
- параметризация:
@ParameterizedTestс@MethodSource, который отдаёт пары «JSON и ожидаемый объект», либо JSON-файлы вsrc/test/resourcesи@ValueSourceс их именами. Каждый набор полей становится отдельным кейсом в отчёте; - тот же маппер, что в проде: в Spring Boot берите
@JsonTestили внедряйте сконфигурированныйObjectMapper. Голыйnew ObjectMapper()ведёт себя иначе: в Jackson 2 он по умолчанию падает на неизвестном поле (FAIL_ON_UNKNOWN_PROPERTIES), а Spring Boot эту опцию выключает; - сравнение: AssertJ
usingRecursiveComparison()сравнивает объект целиком и показывает, какое поле разошлось;assertAllиз JUnit собирает все расхождения за один прогон; - наборы: полный объект; только обязательные поля; лишнее неизвестное поле; явный
null; неверный тип ("age": "abc"), где черезassertThrowsждётеMismatchedInputException.
Главный содержательный момент: примитив int при отсутствии поля станет 0, и тест не отличит «не прислали» от «прислали ноль». Если это важно, поле делают Integer, а обязательность задают через параметр конструктора или компонент record с @JsonProperty(required = true). Опция FAIL_ON_MISSING_CREATOR_PROPERTIES делает обязательными сразу все параметры конструктора.
Где спотыкаются
Пишут в тесте «предполагаем, что по умолчанию 0» и закрепляют случайное поведение библиотеки как требование. Проверять надо то, что описано в контракте API.
Используют в тестах new ObjectMapper(), а в приложении настроенный бин. Тест зелёный, прод падает на лишнем поле, или наоборот.
Проверяют только прямой путь. Круговой тест «объект в JSON и обратно» ловит поля, которые теряются из-за отсутствующего сеттера, @JsonIgnore или неудачного имени.