You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加ZonedDateTime模块后Mockito返回值为Null的问题求助

Spring Boot接口测试NullPointerException排查:ZonedDateTime导致Mockito模拟失效

问题背景

在Spring Boot项目编写接口测试时,原本使用Date类型时测试正常。改用ZonedDateTime类型后,添加了com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.5依赖,并在测试代码中注册了JavaTimeModule,但此时Mockito模拟的bankStatementService.getBankStatementList方法返回值为Null,导致createSuccessResponse方法因参数非空却传入Null而抛出空指针异常。

接口代码

@PostMapping("/bankStatement")
fun getBankStatementList(@Valid @RequestBody request: GenericRequest<BankStatementRequestDTO>): ResponseEntity<ResponseDTO> {
    return createSuccessResponse(bankStatementService.getBankStatementList(request.data))
}

测试代码

fun getBankStatementListSuccess() {
    val DEFAULT_DATE:ZonedDateTime  = ZonedDateTime.ofInstant(Instant.ofEpochMilli(0L), ZoneOffset.UTC);
    val request = GenericRequest(
        BankStatementRequestDTO(
            10,
            1,
            "",
            emptyList(),
            DEFAULT_DATE,
            DEFAULT_DATE,
            "03b3238c-66bb-4a4a-b205-4a9e8231b420"
        )
    )
    val response =
        BankStatementListResponseDTO(
            listOf(
                BankStatementResponseDTO(
                    "XXX123",
                    "CREDIT",
                    "upi-123213",
                    "03b3238c-66bb-4a4a-b205-4a9e8231b420",
                    "UPI",
                    BigDecimal(1234),
                    "remarks",
                    DEFAULT_DATE,
                    DEFAULT_DATE,
                    "CLAIMED",
                    "COIN12345678900"
                )
            ),
            1
        )

    Mockito.`when`(bankStatementService.getBankStatementList(request.data)).thenReturn(response)
    val objectMapper = jacksonObjectMapper()
    objectMapper.registerModule(JavaTimeModule())
    mvc.perform(
        MockMvcRequestBuilders
            .post("/api/v1/bankStatement")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(request))
    ).andExpect(MockMvcResultMatchers.status().isOk)
        .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
}

错误信息

Request processing failed; nested exception is java.lang.NullPointerException: Parameter specified as non-null is null: method com.coinomerelaunch.brokeradminbackend.shared.dto.ResponseAdapterKt.createSuccessResponse, parameter dto
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException: Parameter specified as non-null is null: method com.coinomerelaunch.brokeradminbackend.shared.dto.ResponseAdapterKt.createSuccessResponse, parameter dto
    at app//org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)

问题原因

Mockito的方法匹配依赖对象的相等性判断。测试中构造的BankStatementRequestDTO实例,和接口通过Jackson反序列化得到的实例不是同一个对象;且ZonedDateTime的序列化/反序列化细节(比如时区格式、序列化字符串的一致性),加上如果BankStatementRequestDTO未正确重写equals和hashCode方法,会导致两个对象的相等性判断失败,Mockito无法匹配到预设的方法调用,最终返回默认的Null值。

解决方案

1. 使用Mockito参数匹配器

放弃直接用具体对象匹配,改用匹配器确保方法调用被正确捕获:

// 匹配任意BankStatementRequestDTO类型参数
Mockito.`when`(bankStatementService.getBankStatementList(any(BankStatementRequestDTO::class.java))).thenReturn(response)

// 或自定义字段校验逻辑
Mockito.`when`(bankStatementService.getBankStatementList(argThat { 
    it.pageSize == 10 && it.pageNumber == 1 && it.merchantId == "03b3238c-66bb-4a4a-b205-4a9e8231b420"
})).thenReturn(response)

2. 确保DTO重写equals和hashCode

如果BankStatementRequestDTO不是用Kotlin的data class定义的,手动基于所有字段(包括ZonedDateTime字段)重写equals和hashCode方法;如果是data class,Kotlin会自动生成正确的相等性逻辑,能保证序列化前后的对象相等。

3. 统一ObjectMapper配置

测试中手动创建的ObjectMapper可能和Spring容器中的配置不一致,导致ZonedDateTime序列化/反序列化存在差异。建议注入Spring管理的ObjectMapper并确保其注册了JavaTimeModule:

@Autowired
lateinit var objectMapper: ObjectMapper

@BeforeEach
fun setUp() {
    objectMapper.registerModule(JavaTimeModule())
}

内容的提问来源于stack exchange,提问作者Anurag Parothia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:40:44