1. 概述

在对使用 Jackson 进行 JSON 反序列化的代码做单元测试时,一个高效的策略是 mock ObjectMapper#readValue() 方法。✅

这样做最大的好处是:无需在测试中构造冗长的 JSON 字符串输入,直接控制方法返回值,让测试更专注逻辑本身,而不是被数据格式绊住。

本文将演示如何使用 Mockito 实现这一目标,简洁高效,适合日常开发中“踩坑”后快速验证修复。


2. Maven 依赖

测试需要用到 Mockito 和 Jackson 的核心模块,以下是关键依赖:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.11.0</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>

⚠️ 注意:jackson-databind 是 Jackson 反序列化的基础,务必引入。版本无需严格一致,但建议保持项目统一。


3. ObjectMapper 使用示例

先看一个简单的 Flower 类:

public class Flower {

    private String name;
    private Integer petals;

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

    // 默认构造函数、getter 和 setter 省略
    public String getName() {
        return name;
    }

    public Integer getPetals() {
        return petals;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPetals(Integer petals) {
        this.petals = petals;
    }
}

接下来是一个校验 JSON 字符串是否表示“有花瓣的花”的类:

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

✅ 关键设计:ObjectMapper 通过构造函数注入 —— 这为后续 mock 提供了前提条件,属于典型的可测试性设计。


4. 使用 Mockito 进行单元测试

我们使用 JUnit 5 + Mockito 扩展来简化 mock 管理:

@ExtendWith(MockitoExtension.class)
public class FlowerJsonStringValidatorUnitTest {

    @Mock
    private ObjectMapper objectMapper;

    private FlowerJsonStringValidator flowerJsonStringValidator;

    @BeforeEach
    public void setUp() {
        flowerJsonStringValidator = new FlowerJsonStringValidator(objectMapper);
    }
 
    // 测试用例
}

✅ 编写测试:验证有花瓣的花返回 true

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

关键点解析:

  • when(...).thenReturn(...):直接指定 readValue 返回一个预设的 Flower 实例
  • anyString():表示任意 JSON 字符串输入,无需真实构造
  • eq(Flower.class):确保类型参数匹配,避免泛型擦除问题
  • verify(...):验证 readValue 确实被调用一次,确保逻辑路径正确

⚠️ 踩坑提示:如果不加 eq(Flower.class),可能会因参数匹配失败导致 mock 不生效,这是 Mockito 常见陷阱。


5. 总结

通过 mock ObjectMapper#readValue(),我们可以:

  • ✅ 脱离真实 JSON 字符串,简化测试数据准备
  • ✅ 聚焦业务逻辑(如花瓣数量判断),而非 Jackson 解析细节
  • ✅ 提升测试可读性和维护性,尤其适合复杂嵌套结构的场景

最终代码示例已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/testing-modules/mockito

📌 实践建议:只要 ObjectMapper 是注入的,就大胆 mock;如果是内部 new 出来的,先重构为依赖注入再测试。


原始标题:Mocking the ObjectMapper readValue() Method