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

Java单元测试中如何测试Update方法 现有测试代码是否合理

针对你的问题逐一解答:

1. 你标注的那行when(companyRepository.save(any())).thenReturn(company);是否必要?

在你当前的测试逻辑下属于冗余内容,可以删除。因为你当前的测试只校验了传入save方法的实体属性是否正确,没有校验接口返回的CompanyDTO内容,所以就算不打这个桩,测试也能正常运行。

但如果你后续要补全DTO返回值的校验逻辑,这行桩就需要保留——你甚至可以返回一个全新构造的、已更新的Company实例,来验证你的业务代码确实是用save方法返回的结果来构造DTO,而不是直接用了修改后的原实体。

2. 你当前的测试还存在哪些遗漏?

  • 缺少返回值校验:仅校验了入参正确,没有确认最终返回的CompanyDTO属性和预期更新后的属性一致。
  • 缺少异常场景覆盖:没有测试uuid不存在、findByUuid返回空的场景,此时业务代码应该抛出EntityNotFoundException,且save方法不会被调用。
  • 缺少非更新字段校验:如果你的Company实体还有其他字段(比如uuid、创建时间等),需要确认这些字段不会被update方法意外修改。

3. 关于@Spy和@Captor的选择

你用@Captor是完全正确的,这里不需要用@Spy。@Spy用于对真实对象的行为进行监听和部分桩化,你这里只需要捕获save方法的入参,验证实体的更新逻辑是否正确,用@Captor是最优选择。


优化后的测试示例:

@InjectMocks
private CompanyServiceImpl companyService;

@Mock
private CompanyRepository companyRepository;

@Captor
ArgumentCaptor<Company> companyCaptorEntity;    

@Test
public void testUpdate_正常更新成功() {
    // 1. 构造测试数据
    final UUID uuid = UUID.randomUUID();
    final String updatedName = "更新后的公司名称";
    final CompanyRequest request = new CompanyRequest();
    request.setName(updatedName);

    final Company originalCompany = new Company();
    originalCompany.setUuid(uuid);
    originalCompany.setName("原始公司名称");
    
    // 2. 打依赖桩
    when(companyRepository.findByUuid(uuid)).thenReturn(Optional.of(originalCompany));
    // 这里返回一个新构造的实例,验证业务代码确实用了save的返回值构造DTO
    final Company savedCompany = new Company();
    savedCompany.setUuid(uuid);
    savedCompany.setName(updatedName);
    when(companyRepository.save(any(Company.class))).thenReturn(savedCompany);

    // 3. 执行测试方法
    CompanyDTO result = companyService.update(request, uuid);

    // 4. 校验调用逻辑
    Mockito.verify(companyRepository).findByUuid(uuid);
    Mockito.verify(companyRepository).save(companyCaptorEntity.capture());
    
    // 5. 校验传入save的实体属性正确
    Company capturedCompany = companyCaptorEntity.getValue();
    assertEquals(updatedName, capturedCompany.getName());
    assertEquals(uuid, capturedCompany.getUuid()); // 确认非更新字段未被修改
    
    // 6. 校验返回DTO符合预期
    assertEquals(updatedName, result.getName());
    assertEquals(uuid, result.getUuid());
}

@Test
public void testUpdate_uuid不存在_抛出异常() {
    // 1. 构造测试数据
    final UUID notExistsUuid = UUID.randomUUID();
    final CompanyRequest request = new CompanyRequest();
    request.setName("测试名称");
    
    // 2. 打依赖桩,返回空
    when(companyRepository.findByUuid(notExistsUuid)).thenReturn(Optional.empty());
    
    // 3. 执行并校验抛出指定异常
    assertThrows(EntityNotFoundException.class, () -> companyService.update(request, notExistsUuid));
    
    // 4. 校验save方法未被调用
    Mockito.verify(companyRepository, never()).save(any());
}

内容的提问来源于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 16:06:11