【问题标题】:JUnit test to delete an entity by id fails通过 id 删除实体的 JUnit 测试失败
【发布时间】:2022-01-23 18:05:06
【问题描述】:

我正在尝试测试通过 id 删除实体的方法。我已经为具有给定 id 的实体不存在的情况编写了测试,但如果实体存在,我显然做错了什么。这是服务中的删除方法。我正在使用JpaRepositorydeleteById() 方法。

  public void deleteById(Integer id) {
        Optional<Agency> optionalAgency = repo.findAll().stream()
                .filter(agency -> agency.getId().equals(id))
                .findFirst();

        if (optionalAgency.isPresent()) {
            repo.deleteById(optionalAgency.get().getId());
        } else {
            throw new AgencyNotFoundException("Agency not found");
        }
    }

这是我的测试:

    @Mock
    private AgencyRepository agencyRepository;

    @Mock
    private AgencyMapper mapper;

    @InjectMocks
    private AgencyService agencyService;

    @Test
    void delete() {
        Agency agency = new Agency();

        when(agencyRepository.findById(1)).thenReturn(Optional.of(agency));

        agencyService.deleteById(1);

        verify(agencyRepository).deleteById(1);

    }

我应该做出什么断言来验证删除是否成功?我尝试过的方式不起作用,测试的结果是抛出异常。我猜测抛出异常是因为agencyRepository.findById((int) 1L); 基本上不存在了,但我想也许有更好的方法来验证删除,而无需搜索已删除的对象。

【问题讨论】:

  • 你为什么要做一个浮点数,只是为了把它解析成一个int?只需删除 (int) 和 L。无论哪种方式,您都比我们更了解您的 AgencyRepository 的代码,因此您应该检查该方法是否存在
  • 我的 AgencyRepository 中唯一的代码是 @Repository public interface AgencyRepository extends JpaRepository&lt;Agency, Integer&gt; {},我必须将参数传递给 delete 方法。我试过直接传递一个 int(例如 1),但测试失败并出现同样的错误

标签: java unit-testing junit spring-data-jpa mockito


【解决方案1】:

不是答案,但你的方法可以写成这样:

 public void deleteById(Integer id) {
     Agency agency = repo.findById(id).orElseThrow(() -> throw new AgencyNotFoundException("Agency not found"));
     repo.deleteById(agency.getId());
 }

因为:

  • Optional&lt;Agency&gt; optionalAgency = repo.findAll().stream().filter(agency -&gt; agency.getId().equals(id)).findFirst(); 效率不高。如果你有成千上万的机构怎么办?您是否会获取所有内容并过滤所有内容,以便通过 id 查找。您的存储库中已经有了该方法。
  • if (optionalAgency.isPresent()) {} Optional.isPresent 不是好的做法。阅读herethis answer

【讨论】:

  • 哦好的,我明白了,有道理,谢谢!
  • @Alessia 不客气!
【解决方案2】:

repo 是一个模拟,因此在其上调用deleteById 实际上不会删除任何内容。相反,您可以验证调用AgencyServicedeleteById 实际上调用了AgencyRepositorydeleteById

编辑:
存储库的代码使用findAll,而不是findById,因此您需要确保模拟它:

@Test
void delete() {
    Agency agency = new Agency();
    agenct.setId((int) 1L);

    when(agencyRepository.findAll()).thenReturn(Collections.singletonList(agency));

    agencyService.deleteById((int) 1L);

    verify(agencyRepository).delteById((int) 1L);
}

【讨论】:

  • 好的,我明白了,所以我在这里能做的就是验证正确的流程。我已按照您建议的方式更改了代码,但它仍然引发异常。
  • @Alessia 你能发布异常或错误的输出吗
  • @Alessia 我认为嘲笑是错误的 - 请参阅我编辑的答案
  • 嗯,好的,但是我怎样才能从返回列表的agencyRepository.findAll() 返回Optional.of(agency)?这会导致错误。这是我在将方法切换为findAll()之前遇到的错误:com.project.exceptions.AgencyNotFoundException: Agency not found at com.project.services.AgencyService.deleteById(AgencyService.java:39) at com.project.AgencyServiceTest.delete(AgencyServiceTest.java:64) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
  • @Alessia 抱歉,这是一个粗心的部分编辑。您应该模拟 findAll() 并返回一个包含模拟的 Agency 对象的列表。请参阅我的进一步编辑。
猜你喜欢
  • 2016-10-31
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 2014-11-24
  • 2021-12-22
  • 2013-11-08
  • 1970-01-01
  • 2014-04-26
相关资源
最近更新 更多