如何为Hamcrest的containsInAnyOrder匹配器传入自定义比较器
解决方案:Hamcrest中使用自定义比较逻辑实现测试断言
答案是肯定的,Hamcrest完全支持在不修改MyDto原有equals/hashCode方法的前提下,通过自定义比较逻辑完成测试断言。以下是两种实用的实现方式:
方法一:结合comparesEqualTo与自定义Comparator
直接创建一个忽略f2字段的比较器,让containsInAnyOrder使用这个测试专属的比较规则来匹配对象。
1. 编写忽略f2的Comparator
Comparator<MyDto> ignoreF2Comparator = (dto1, dto2) -> { // 先比较f1,不相等直接返回结果 int f1Compare = dto1.getF1().compareTo(dto2.getF1()); if (f1Compare != 0) { return f1Compare; } // f1相等时比较f3 return dto1.getF3().compareTo(dto2.getF3()); };
2. 在断言中使用该Comparator
用comparesEqualTo包装预期的MyDto对象,传入自定义比较器即可:
var actualList = service.getActualList(...); assertThat(actualList, containsInAnyOrder( comparesEqualTo(new MyDto("a1", "", "c1"), ignoreF2Comparator), comparesEqualTo(new MyDto("a2", "", "c2"), ignoreF2Comparator) ));
方法二:编写自定义Hamcrest匹配器
如果这类测试逻辑需要多次复用,可以编写一个专属的匹配器类,让断言代码更简洁,且失败时的错误描述更清晰。
1. 实现自定义匹配器
public class MyDtoIgnoringF2Matcher extends TypeSafeMatcher<MyDto> { private final MyDto expected; public MyDtoIgnoringF2Matcher(MyDto expected) { this.expected = expected; } @Override protected boolean matchesSafely(MyDto actual) { // 仅比较f1和f3字段 return expected.getF1().equals(actual.getF1()) && expected.getF3().equals(actual.getF3()); } @Override public void describeTo(Description description) { description.appendText("MyDto匹配f1=" + expected.getF1() + "、f3=" + expected.getF3()); } // 静态工厂方法,简化调用 public static MyDtoIgnoringF2Matcher matchesMyDtoIgnoringF2(MyDto expected) { return new MyDtoIgnoringF2Matcher(expected); } }
2. 在断言中使用自定义匹配器
var actualList = service.getActualList(...); assertThat(actualList, containsInAnyOrder( matchesMyDtoIgnoringF2(new MyDto("a1", "", "c1")), matchesMyDtoIgnoringF2(new MyDto("a2", "", "c2")) ));
说明
两种方式都完全隔离了测试逻辑与业务代码,不会对MyDto的业务行为造成任何影响。第一种方式轻量快捷,适合简单场景;第二种方式更适合需要重复使用的测试逻辑,且能提供更友好的断言失败提示。
内容的提问来源于stack exchange,提问作者gstackoverflow
相关产品推荐
相关产品推荐

