使用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
相关产品推荐
相关产品推荐

