我们有一个包含多个字段的自定义类,我们无法为业务域原因覆盖equals / hashcode方法
然而,在单元测试期间,我们应断言集合是否包含此类的项目
List<CustomClass> customObjectList = classUnderTest.methodUnderTest();
//create customObject with fields set to the very same values as one of the elements in customObjectList
//we should assert here that customObjectList contains customObject
但是,到目前为止,我们没有找到任何可以在不覆盖equals / hashcode的情况下工作的解决方案,例如Hamcrest
assertThat(customObjectList, contains(customObject));
导致AssertionError引用
Expected: iterable containing [<CustomClass@578486a3>]
but: item 0: was <CustomClass@551aa95a>
是否有解决方案而无需逐场比较?
答案 0 :(得分:4)
如果您使用的是Java8,则可以使用Stream#anyMatch和您自己的customEquals方法。像这样的东西会起作用 -
assertTrue(customObjectList.stream()
.anyMatch(object -> customEquals(object,customObject)));
更新以反映Holger的评论
答案 1 :(得分:1)
Fest Assertions具有以下内容:
assertThat(expected).isEqualsToByComparingFields(actual);
我认为它在引擎盖下进行了反思比较。我们遇到了类似的问题,这使我们免于编写自定义比较逻辑。
另一件事是扩展您选择的断言框架,以适合您的确切类和案例。这种方法应该减少使用深度反射比较的一些性能开销。
答案 2 :(得分:1)
assertj擅长这一点。尤其是custom comparison strategy
private static class CustomClass {
private final String string;
CustomClass(String string) {
this.string = string;
}
// no equals, no hashCode!
}
@Test
public void assertjToTheRescue() {
List<CustomClass> list = Arrays.asList(new CustomClass("abc"));
assertThat(list).usingFieldByFieldElementComparator().contains(new CustomClass("abc"));
}
assertj提供了许多其他usingComparator
方法。
答案 3 :(得分:0)
没有
Collection
接口的许多方法都是根据equals()
明确定义的。例如。 Collection#contains()
:
如果此集合包含指定的元素,则返回
true
。更多 正式地,当且仅当此集合包含at时返回true
至少一个元素e
,(o==null ? e==null : o.equals(e))
。
只为每个按字段收集和比较字段。您可以将比较/等于逻辑存储到静态实用程序类中,如CustomClasses
或类似,然后编写自定义Hamcrest匹配器。
或者,使用反射等于,例如来自Apache Commons Lang,Hamcrest extension或(最好)迁移到AssertJ,has this functionality out of the box:
assertThat(ImmutableList.of(frodo))
.usingFieldByFieldElementComparator()
.contains(frodoClone);
这是一个黑客和狡猾,但足够的测试。请不要在生产代码中使用。
答案 4 :(得分:0)
我知道使用Hamcrest的两个解决方案。第一个测试项目的一些属性。
assertThat(customObjectList, contains(allOf(
hasProperty("propertyA", equalTo("someValue")),
hasProperty("propertyB", equalTo("anotherValue")))));
或者您可以使用Nitor Creations中的reflectEquals
匹配器:
assertThat(customObjectList, contains(reflectEquals(customObject)));