如何为Java中的软删除delete方法编写正确的单元测试
问题根因分析
你最开始的测试没有抛出预期异常,本质是两个逻辑错误导致的:
- 你已经通过
Mockito.when(companyRepository.findByUuid(uuid)).thenReturn(Optional.of(company))给这个方法调用打了桩,只要入参是对应uuid,不管调用多少次都会返回你指定的存在的Company实例,自然不会触发orElseThrow抛出的EntityNotFoundException - 你的软删除逻辑是标记
deleted=true的逻辑删除,不是物理删除,如果你没有给companyRepository.findByUuid方法额外加deleted=false的查询过滤,哪怕实体被标记为删除,调用该方法还是会返回数据,不会抛异常
现有测试优化建议
你更新后的两个测试已经覆盖了Service层的核心分支(正常删除、不存在时抛异常),还可以做如下优化让测试更严谨:
1. 正常删除场景测试优化
不需要mock掉deletionService.delete方法,直接注入真实的DeletionService实例,就可以同时验证软删除字段是否被正确赋值,比单纯验证方法调用更有业务价值:
@Test public void test_Successful_Delete() { // Arrange final String name = "Company"; final Company company = new Company(name); UUID mockUserUuid = UUID.randomUUID(); Instant mockNow = Instant.now(); // 给deletionService依赖的currentUser、clock打桩 when(currentUser.getUuid()).thenReturn(mockUserUuid); when(clock.millis()).thenReturn(mockNow.toEpochMilli()); when(companyRepository.findByUuid(company.getUuid())) .thenReturn(Optional.of(company)); when(companyRepository.save(isA(Company.class))).thenReturn(company); // Act companyService.delete(company.getUuid()); // Assert // 验证方法调用 verify(deletionService, times(1)).delete(isA(Company.class)); verify(companyRepository, times(1)).save(isA(Company.class)); // 验证软删除字段被正确设置 assertTrue(company.isDeleted()); assertEquals(mockNow, company.getDeleteDate()); assertEquals(mockUserUuid, company.getDeletedByUserUuid()); }
2. 不存在抛异常场景优化
可以加验证确认删除、保存逻辑没有被执行,避免逻辑漏洞:
@Test(expected = EntityNotFoundException.class) public void test_Delete_thenThrowException() { // Arrange UUID notExistUuid = UUID.randomUUID(); when(companyRepository.findByUuid(notExistUuid)).thenReturn(Optional.empty()); // Act companyService.delete(notExistUuid); // Assert (抛出异常后下面的验证依然会生效) verify(deletionService, never()).delete(any()); verify(companyRepository, never()).save(any()); }
额外说明
如果你需要测试「软删除后通过业务查询接口查不到对应数据」的逻辑,这属于Repository层的测试范围,需要你先给findByUuid方法加上软删除过滤(比如JPA场景给实体加@Where(clause = "deleted = false")注解,或者自定义查询语句加过滤条件),再通过集成测试注入真实Repository验证即可,不需要在Service单元测试里覆盖这个场景。
内容的提问来源于stack exchange,提问作者user17186249
相关产品推荐
相关产品推荐

