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

Service层删除方法Mockito测试失败问题求助

问题排查与解决

我来帮你理清这个问题的核心所在——你的Service层实际调用的Repository方法,和测试代码里验证的方法根本不是同一个,这才导致了测试失败,咱们拆解来看:

问题根源

  1. Service层的实际操作:你的deletePerson方法里调用的是personRepository.delete(personOptional.orElse(new Person())),这是Spring Data JPA中接收实体对象的delete(T entity)方法;
  2. 测试代码的验证逻辑:但你在测试里写的是Mockito.verify(personRepository, times(1)).deleteById(1l),验证的是接收ID参数的deleteById(Long id)方法。

这两个是完全独立的方法,Mockito会严格匹配方法签名,所以它会告诉你“期望的deleteById没被调用”,同时列出实际发生的两次交互:findById和delete(空Person)。

另外,你的Service逻辑还有个小问题:当personOptional为空(也就是要删除的Person不存在时),orElse(new Person())会创建一个空的Person对象并传给delete,这其实是无意义的操作——删除一个不存在的实体不会有任何数据库变更,还会导致不必要的对象创建。

解决方案

你可以根据需求选择以下两种修复方式:

方案一:修改Service层,改用deleteById(推荐)

这种方式更简洁高效,也能和你的测试逻辑匹配:

public Optional<PersonDto> deletePerson(Long id) {
    Assert.notNull(id, "id can't be null");
    Optional<Person> personOptional = personRepository.findById(id);
    // 只在Person存在时执行删除,或者直接调用deleteById(id)(不存在时也不会报错)
    personOptional.ifPresent(p -> personRepository.deleteById(id));
    // 或者直接写:personRepository.deleteById(id);
    return personOptional.map(p -> modelMapper.map(p, PersonDto.class));
}

修改后,你的原测试代码verify(personRepository, times(1)).deleteById(1l)就能正常通过了。

方案二:修改测试代码,匹配Service层的delete方法

如果不想改动Service逻辑,就需要调整测试来验证delete方法的调用:

@Test
public void shouldDeletePersonById() {
    // 先mock findById的返回,模拟存在id=1的Person
    Person mockPerson = new Person();
    mockPerson.setId(1L);
    when(personRepository.findById(1L)).thenReturn(Optional.of(mockPerson));
    
    personService.deletePerson(1L);
    
    // 验证调用delete方法,传入的是我们mock的Person对象
    Mockito.verify(personRepository, times(1)).delete(mockPerson);
}

如果要测试Person不存在的场景,因为orElse(new Person())每次都会生成新对象,你可以用Mockito.any(Person.class)来匹配:

@Test
public void shouldDoNothingWhenPersonNotFound() {
    when(personRepository.findById(999L)).thenReturn(Optional.empty());
    
    personService.deletePerson(999L);
    
    Mockito.verify(personRepository, times(1)).delete(Mockito.any(Person.class));
}

额外优化建议

把Service里的personRepository.delete(personOptional.orElse(new Person()))改成personOptional.ifPresent(personRepository::delete),这样只有当Person存在时才会执行删除操作,避免无意义的空对象删除。

内容的提问来源于stack exchange,提问作者Magdalena Rumakowicz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:17:38