如何用JUnit测试基于Comparator thenComparing的List排序逻辑
为什么你的多字段排序测试会失败?
咱们先拆解下你的问题:你写的JUnit测试错误地认为每一对相邻元素都必须满足所有三个排序条件,但实际上多字段排序是优先级递进的——只有当前面的排序字段完全相等时,才需要验证后面的字段。
先明确你的排序逻辑:
- 第一优先级:按
getA()降序排列(数值大的在前) - 第二优先级:当
A字段相等时,按Y.isX()升序排列(false在前,true在后,因为Boolean的自然排序中false<true) - 第三优先级:当
A和Y.isX()都相等时,按getB()升序排列(字符串自然排序,字典序小的在前)
你的测试代码对每一对元素都强制检查三个断言,比如即使current.getA()远大于next.getA(),你还要求current.getY().isX()必须大于next.getY().isX(),这完全违背了排序的优先级规则,所以后面的断言必然失败。
正确的测试实现方式
方式一:按优先级分步断言(手动校验)
我们需要对每一对相邻元素按排序优先级逐步判断,只有当前面的字段相等时,才继续校验后面的条件:
IntStream.range(0, list.size() - 1).forEach(i -> { ObjectA current = list.get(i); ObjectA next = list.get(i + 1); // 校验第一优先级:A字段降序 int aComparison = Integer.compare(current.getA(), next.getA()); if (aComparison > 0) { // current的A更大,符合降序要求,无需继续校验后续字段 return; } else if (aComparison == 0) { // A字段相等,校验第二优先级:Y.isX()升序 boolean currentX = current.getY().isX(); boolean nextX = next.getY().isX(); int xComparison = Boolean.compare(currentX, nextX); if (xComparison < 0) { // current的X是false,next是true,符合升序要求,无需校验B字段 return; } else if (xComparison == 0) { // X字段也相等,校验第三优先级:B字段升序 assertTrue(current.getB().compareTo(next.getB()) <= 0, String.format("B字段排序错误:%s 应该排在 %s 之前", current.getB(), next.getB())); } else { // current的X是true,next是false,不符合升序 fail(String.format("X字段排序错误(A字段相等时):%b 不应该排在 %b 之前", currentX, nextX)); } } else { // current的A比next小,不符合降序 fail(String.format("A字段排序错误:%d 不应该排在 %d 之前", current.getA(), next.getA())); } });
方式二:复用排序Comparator(更简洁可靠)
其实你完全可以直接复用排序时使用的Comparator来验证列表的顺序,这样既避免手动写断言的逻辑错误,又让测试代码更简洁:
// 复用你排序时使用的Comparator Comparator<ObjectA> expectedComparator = Comparator.comparing(ObjectA::getA) .reversed() .thenComparing(a -> a.getY().isX()) .thenComparing(ObjectA::getB); // 验证列表中的每一对相邻元素都符合预期Comparator的排序规则 for (int i = 0; i < list.size() - 1; i++) { ObjectA current = list.get(i); ObjectA next = list.get(i + 1); int comparisonResult = expectedComparator.compare(current, next); // 排序后的列表中,current应该小于等于next(因为Comparator返回<=0表示current应该在前) assertTrue(comparisonResult <= 0, String.format("元素顺序错误:%s 应该排在 %s 之前", current, next)); }
这种方法的优势在于:如果后续你的排序逻辑有修改,只需要同步修改expectedComparator即可,不需要手动调整断言逻辑,大大降低了维护成本。
内容的提问来源于stack exchange,提问作者emoleumassi
相关产品推荐
相关产品推荐

