You need to enable JavaScript to run this app. 使用Mockito测试Service时JPARepository.save返回null引发空指针异常
优惠活动
大模型
产品
解决方案
定价
更多

使用Mockito测试Service时JPARepository.save返回null引发空指针异常

问题原因

你使用@Mock注解修饰了PatientRepository,Mockito的模拟对象默认行为是:所有非void方法在未手动指定返回值(打桩)时,默认返回null。你提到的转换前不为空的是mapper.from(patientModel)得到的patientEntity,但后续调用repository.save(patientEntity)时,没有给这个save方法配置模拟返回值,所以得到的savedPatient是null,这个null值作为参数传给Mapper的from方法后,就触发了空指针异常。

解决方案

方案1:给Mock的Repository方法手动打桩(单元测试推荐)

在测试方法调用serviceUnderTests.create()之前,添加如下打桩逻辑,指定save方法的返回值:

// 构造save方法要返回的模拟实体
PatientEntity mockSavedEntity = new PatientEntity();
mockSavedEntity.setId(134);
mockSavedEntity.setFirstName("Pawel");
mockSavedEntity.setLastName("Nowak");
mockSavedEntity.setEmail("pawel@test.pl");
mockSavedEntity.setPhone("123456789");

// 给save方法打桩:传入任意PatientEntity时返回构造好的mockSavedEntity
Mockito.when(patientRepository.save(Mockito.any(PatientEntity.class))).thenReturn(mockSavedEntity);

另外你原测试的断言逻辑也存在问题:assertNotNull(patientRepository.findAll())中的findAll也是Mock方法,默认也会返回null,你可以改成验证save方法是否被正确调用,或者验证返回的PatientModel字段符合预期,调整后的测试示例如下:

@Test
void whenCreatePatientByService_thenSaveIsCalledAndResultMatch() {
    PatientModel patientModel = new PatientModel(134, "Pawel", "Nowak", 
    "pawel@test.pl", "123456789");
    // 上面的打桩逻辑省略
    PatientModel result = serviceUnderTests.create(patientModel);

    // 验证save方法被调用了1次
    Mockito.verify(patientRepository, Mockito.times(1)).save(Mockito.any(PatientEntity.class));
    // 验证返回结果的字段符合预期
    assertEquals(134, result.getId());
    assertEquals("Pawel", result.getFirstName());
}

方案2:使用JPA集成测试

如果你需要测试真实的Repository持久化逻辑,可以改用@DataJpaTest注解修饰测试类,此时Spring会注入真实的JPA Repository实现,save方法会正常返回带ID的持久化实体,不需要手动打桩。

内容的提问来源于stack exchange,提问作者Paweł Nowak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 16:57:00