如何用JUnit测试Rest API的Update方法?测试触发EntityNotFoundException
问题分析与解决方案
你的测试代码存在几个关键问题,导致抛出EntityNotFoundException:
- 错误Mock了被测试类的方法:你在测试中Mock了
applicantService.update(),这相当于跳过了真实的更新逻辑,完全失去了单元测试的意义——单元测试要验证的就是这个方法的真实行为,不能Mock它自己。 - 未Mock依赖的Repository查询逻辑:
update()方法调用了getById(id),而getById底层依赖applicantRepository.findById(),你没有Mock这个方法的返回值,导致它返回空Optional,触发了实体找不到的异常。 - 测试逻辑完全偏离:你没有实际调用
applicantService.update()方法,只是断言了两个预设对象的属性,根本没测试到update的业务逻辑。 - 参数传递错误:测试中使用
Mockito.any()作为update的id参数,但实际调用时没有传入有效的id值,导致id为null,这也是报错里显示id : null的直接原因。
修正后的测试代码
@ExtendWith(MockitoExtension.class) class ApplicantServiceTest { @Mock private ApplicantRepository applicantRepository; @Mock private CreditRatingService creditRatingService; @Mock private ApplicantMapper applicantMapper; @InjectMocks private ApplicantService applicantService; @Test void update() { // 1. 准备测试数据:原有的申请人数据(确保id不为空) Long applicantId = 1L; Applicant originalApplicant = getSampleApplicants().get(1); originalApplicant.setId(applicantId); // 2. 构造要更新的DTO(模拟前端传入的更新请求) ApplicantDTO updateDTO = new ApplicantDTO(); updateDTO.setFirstName("ege"); updateDTO.setLastName("c0skun"); updateDTO.setMonthlyIncome(2523); updateDTO.setPhoneNumber("21412412"); updateDTO.setIdentificationNumber(2141245L); // 3. Mock Repository的findById方法,确保getById能拿到数据 Mockito.when(applicantRepository.findById(applicantId)) .thenReturn(Optional.of(originalApplicant)); // 4. 构造预期的更新后数据(与DTO中的更新字段对应) Applicant expectedUpdatedApplicant = new Applicant(); BeanUtils.copyProperties(originalApplicant, expectedUpdatedApplicant); expectedUpdatedApplicant.setFirstName(updateDTO.getFirstName()); expectedUpdatedApplicant.setLastName(updateDTO.getLastName()); expectedUpdatedApplicant.setMonthlyIncome(updateDTO.getMonthlyIncome()); expectedUpdatedApplicant.setPhoneNumber(updateDTO.getPhoneNumber()); expectedUpdatedApplicant.setIdentificationNumber(updateDTO.getIdentificationNumber()); // 5. Mock Repository的save方法返回预期结果 Mockito.when(applicantRepository.save(Mockito.any(Applicant.class))) .thenReturn(expectedUpdatedApplicant); // 6. 实际调用要测试的update方法 Applicant actualUpdatedApplicant = applicantService.update(updateDTO, applicantId); // 7. 断言更新后的属性是否符合预期 Assert.assertEquals(expectedUpdatedApplicant.getIdentificationNumber(), actualUpdatedApplicant.getIdentificationNumber()); Assert.assertEquals(expectedUpdatedApplicant.getPhoneNumber(), actualUpdatedApplicant.getPhoneNumber()); Assert.assertEquals(expectedUpdatedApplicant.getFirstName(), actualUpdatedApplicant.getFirstName()); Assert.assertEquals(expectedUpdatedApplicant.getMonthlyIncome(), actualUpdatedApplicant.getMonthlyIncome()); Assert.assertEquals(expectedUpdatedApplicant.getId(), actualUpdatedApplicant.getId()); // 8. 验证Repository方法是否被正确调用 Mockito.verify(applicantRepository, Mockito.times(1)).findById(applicantId); Mockito.verify(applicantRepository, Mockito.times(1)).save(Mockito.any(Applicant.class)); } }
关键修正点说明
- Mock Repository核心方法:通过
Mockito.when(applicantRepository.findById(applicantId))预设查询结果,确保getById(id)能拿到有效数据,避免抛出异常。 - 调用真实业务方法:直接调用
applicantService.update(),传入构造好的DTO和有效id,触发真实的更新逻辑。 - 验证依赖调用:使用
Mockito.verify()确认Repository的查询和保存操作确实被执行,保证业务逻辑的完整性。 - 明确数据流向:从原始数据→更新DTO→预期结果→实际结果,完整覆盖update方法的业务流程。
内容的提问来源于stack exchange,提问作者Ege Coskun
相关产品推荐
相关产品推荐

