Jackson Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

When unit testing code that involves deserializing JSON with Jackson, we might find it easier to mock the ObjectMapper#readValue method. By doing so, we don't need to specify long JSON inputs in our tests.

In this tutorial, we're going to see how we can achieve this using Mockito.

2. Maven Dependencies

First of all, as Maven dependencies, we're going to use mockito-core and 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.10.3</version>
    <type>bundle</type>
</dependency>

3. An ObjectMapper Example

Let's consider a simple Flower class:

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
}

And suppose we have a class for validating a JSON string representation of a Flower object. It takes ObjectMapper as a constructor argument — this makes it easy for us to mock it later:

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;
    }
}

Next, we'll use Mockito to write unit tests for the validator logic.

4. Unit Testing With Mockito

Let's start by setting up our test class. We can easily mock an ObjectMapper and pass it as a constructor argument to our FlowerStringValidator class:

@ExtendWith(MockitoExtension.class)
public class FlowerJsonStringValidatorUnitTest {

    @Mock
    private ObjectMapper objectMapper;

    private FlowerJsonStringValidator flowerJsonStringValidator;

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

Note that we're using JUnit 5 in our tests, so we've annotated our test class with @ExtendWith(MockitoExtension.class).

Now that we have our mock ObjectMapper ready to go, let's write a simple test:

@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));
}

Since we're mocking ObjectMapper here, we can ignore its input and focus on its output, which is then passed to the actual validator logic. As we can see, we don't need to specify valid JSON input, which can be very long and difficult in a real-world scenario.

5. Conclusion

In this article, we saw how to mock ObjectMapper to provide efficient test cases around it. Finally, the code can be found over on GitHub.

Jackson bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!