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

Kotlin项目空指针异常:recordPartialWithdrawal非空错误修正指引

Kotlin单元测试空指针异常(recordPartialWithdrawal不能为null)修复方案

问题场景

运行下述Kotlin单元测试代码时触发空指针异常,报错提示:recordPartialWithdrawal不能为null

测试代码

@Test
fun `should record partial Withdrawal`() {
    underTest.recordPartialWithdrawal(defaultUserId, Money.of(200.200, "EUR"), LocalDate.now())
    val paymentRequestHistoryRequestCapture = argumentCaptor()

    verify(paymentRequestHistoryRepository).save<PaymentRequestHistory>(paymentRequestHistoryRequestCapture.capture())
    assertThat(paymentRequestHistoryRequestCapture.firstValue).satisfies(
        Consumer {
            assertThat(it.type).isEqualTo(PaymentRequestType.OUTGOING_PARTIAL_WITHDRAWAL)
            assertThat(it.userId).isEqualTo(defaultUserId)
            assertThat(it.amount).isEqualTo(Money.of(200.200, "EUR"))
        }
    )

    underTest.recordPartialWithdrawal(defaultUserId, Money.of(200.200, "EUR"), LocalDate.now())
}

核心原因

空指针异常直接原因是测试中的underTest实例未正确初始化,调用recordPartialWithdrawal方法时触发NPE。同时代码存在其他潜在问题:

  1. argumentCaptor()未指定泛型类型,存在类型安全隐患
  2. 重复调用recordPartialWithdrawal但未做验证,属于冗余代码

修复步骤

  • 初始化测试实例:确保underTest对应的业务类在测试前完成实例化,依赖的paymentRequestHistoryRepository需通过Mock框架(如MockK/Mockito)初始化并注入。示例(MockK):
    private val paymentRequestHistoryRepository = mockk<PaymentRequestHistoryRepository>()
    private val underTest = YourServiceClass(paymentRequestHistoryRepository) // 替换为实际业务类名
    
  • 指定ArgumentCaptor泛型:明确argumentCaptor的目标类型,避免类型转换问题:
    val paymentRequestHistoryRequestCapture = argumentCaptor<PaymentRequestHistory>()
    
  • 清理冗余代码:删除未做验证的第二次recordPartialWithdrawal调用,或补充对应的验证逻辑
  • 校验参数非空:确认defaultUserId、Money.of(200.200, "EUR")等入参不为null,必要时添加非空断言

修复后完整测试代码示例

import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.assertj.core.api.Assertions.assertThat

class YourServiceClassTest { // 替换为实际测试类名
    private val paymentRequestHistoryRepository = mockk<PaymentRequestHistoryRepository>(relaxed = true)
    private lateinit var underTest: YourServiceClass
    private val defaultUserId = "test-user-id"

    @BeforeEach
    fun setUp() {
        underTest = YourServiceClass(paymentRequestHistoryRepository)
    }

    @Test
    fun `should record partial Withdrawal`() {
        val testAmount = Money.of(200.200, "EUR")
        val testDate = LocalDate.now()

        underTest.recordPartialWithdrawal(defaultUserId, testAmount, testDate)

        val capture = argumentCaptor<PaymentRequestHistory>()
        verify { paymentRequestHistoryRepository.save(capture.capture()) }

        val capturedHistory = capture.firstValue
        assertThat(capturedHistory.type).isEqualTo(PaymentRequestType.OUTGOING_PARTIAL_WITHDRAWAL)
        assertThat(capturedHistory.userId).isEqualTo(defaultUserId)
        assertThat(capturedHistory.amount).isEqualTo(testAmount)
    }
}

内容的提问来源于stack exchange,提问作者nitin sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:45:38