Assertj如何基于索引通过谓词断言列表元素?
基于列表索引的AssertJ断言实现方案
问题场景
你希望针对列表元素的索引进行断言操作,目前已实现的可行方案是使用extracting配合containsExactly和tuple硬编码每个元素的预期值:
// This works: assertThat(tasks).extracting(Task::getId, Task::getExamId).containsExactly( tuple(1, EXAM_ID), tuple(2, EXAM_ID), tuple(3, EXAM_ID), tuple(4, EXAM_ID), tuple(5, EXAM_ID) );
但你想要更具动态性的实现,比如通过带索引的断言逻辑完成验证,尝试的代码无法编译:
// I would rather use something like BiFunction<Integer, Task, Boolean> indexedPredicate = (n, task) -> Objects.equals(task.getId(), n); assertThat(tasks).allSatisfy(indexedPredicate);
解决思路
AssertJ本身没有直接提供带索引参数的allSatisfy重载,但可以通过以下几种方式实现动态索引断言:
利用Stream的zipWithIndex()转换
将列表转为带索引的流,再对每个索引-元素对进行断言,这是最简洁的实现方式:assertThat(tasks.stream().zipWithIndex()) .allSatisfy(entry -> { Task task = entry.getValue(); // 注意索引从0开始,根据业务需求调整偏移量 assertThat(task.getId()).isEqualTo(entry.getIndex() + 1); assertThat(task.getExamId()).isEqualTo(EXAM_ID); });封装自定义断言方法
如果需要频繁使用带索引的断言,可以封装一个通用方法,复用逻辑:public static <T> void assertAllWithIndex(List<T> list, BiFunction<Integer, T, Boolean> predicate) { for (int i = 0; i < list.size(); i++) { T element = list.get(i); assertThat(predicate.apply(i, element)).as("Element at index %s failed", i).isTrue(); } } // 使用示例 assertAllWithIndex(tasks, (index, task) -> Objects.equals(task.getId(), index + 1) && Objects.equals(task.getExamId(), EXAM_ID) );动态生成预期列表(兼容原有写法)
如果想保留containsExactly的风格,可以动态生成预期的tuple列表,避免硬编码:List<Tuple> expectedTuples = IntStream.rangeClosed(1, 5) .mapToObj(id -> tuple(id, EXAM_ID)) .collect(Collectors.toList()); assertThat(tasks).extracting(Task::getId, Task::getExamId).containsExactlyElementsOf(expectedTuples);
内容的提问来源于stack exchange,提问作者Thomas Auinger
相关产品推荐
相关产品推荐

