Перейти к основному содержимому

Насмешка над методом ObjectMapper readValue()

· 2 мин. чтения

1. Обзор

При модульном тестировании кода, включающего десериализацию JSON с помощью Jackson, нам может быть проще имитировать метод ObjectMapper#readValue . Таким образом, нам не нужно указывать длинные входные данные JSON в наших тестах.

В этом уроке мы увидим, как мы можем добиться этого с помощью Mockito .

2. Зависимости Maven

Прежде всего, в качестве зависимостей Maven мы будем использовать mockito-core и jackson-databind :

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
<type>bundle</type>
</dependency>

3. Пример ObjectMapper

Давайте рассмотрим простой класс Flower :

public class Flower {

private String name;
private Integer petals;

public Flower(String name, Integer petals) {
this.name = name;
this.petals = petals;
}

// default constructor, getters and setters
}

Предположим, у нас есть класс для проверки строкового представления JSON объекта Flower . Он принимает ObjectMapper в качестве аргумента конструктора — это позволяет нам легко смоделировать его позже:

public class FlowerJsonStringValidator {
private ObjectMapper objectMapper;

public FlowerJsonStringValidator(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

public boolean flowerHasPetals(String jsonFlowerAsString) throws JsonProcessingException {
Flower flower = objectMapper.readValue(jsonFlowerAsString, Flower.class);
return flower.getPetals() > 0;
}
}

Далее мы будем использовать Mockito для написания модульных тестов для логики валидатора.

4. Модульное тестирование с Mockito

Давайте начнем с настройки нашего тестового класса. Мы можем легко имитировать ObjectMapper и передать его в качестве аргумента конструктора нашему классу FlowerStringValidator :

@ExtendWith(MockitoExtension.class)
public class FlowerJsonStringValidatorUnitTest {

@Mock
private ObjectMapper objectMapper;

private FlowerJsonStringValidator flowerJsonStringValidator;

@BeforeEach
public void setUp() {
flowerJsonStringValidator = new FlowerJsonStringValidator(objectMapper);
}

...
}

Обратите внимание, что мы используем JUnit 5 в наших тестах, поэтому мы аннотировали наш тестовый класс с помощью @ExtendWith(MockitoExtension.class) .

Теперь, когда у нас есть готовый макет ObjectMapper , давайте напишем простой тест:

@Test
public void whenCallingHasPetalsWithPetals_thenReturnsTrue() throws JsonProcessingException {
Flower rose = new Flower("testFlower", 100);

when(objectMapper.readValue(anyString(), eq(Flower.class))).thenReturn(rose);

assertTrue(flowerJsonStringValidator.flowerHasPetals("this can be a very long json flower"));

verify(objectMapper, times(1)).readValue(anyString(), eq(Flower.class));
}

Поскольку здесь мы издеваемся над ObjectMapper , мы можем игнорировать его ввод и сосредоточиться на его выводе , который затем передается фактической логике валидатора. Как мы видим, нам не нужно указывать допустимый ввод JSON, который может быть очень длинным и сложным в реальном сценарии.

5. Вывод

В этой статье мы увидели, как имитировать ObjectMapper , чтобы создать вокруг него эффективные тестовые примеры. Наконец, код можно найти на GitHub .