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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 04:36:03