来自 JUnit4/JUnit 5 的assertEquals(Object, Object) 或来自 Hamcrest 的assertThat(actual, is(expected)); 在其他答案中提出的仅当equals() 和toString() 被比较对象的类(和深度)覆盖时才有效。
这很重要,因为断言中的相等测试依赖于equals(),而测试失败消息依赖于比较对象的toString()。
对于诸如String、Integer 之类的内置类……没问题,因为它们同时覆盖了equals() 和toString()。所以用assertEquals(Object,Object)断言List<String>或List<Integer>是完全有效的。
关于这个问题:你必须在一个类中覆盖equals(),因为它在对象相等方面是有意义的,不仅是为了让 JUnit 测试中的断言更容易。
为了使断言更容易,您还有其他方法。
作为一个好习惯,我喜欢断言/匹配器库。
这是一个AssertJ 解决方案。
org.assertj.core.api.ListAssert.containsExactly() 是您所需要的:它验证实际组是否完全包含给定值,而没有其他内容,按照 javadoc 中所述的顺序。
假设有一个 Foo 类,您可以在其中添加元素以及获取元素的位置。
断言两个列表具有相同内容的Foo 的单元测试可能如下所示:
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
@Test
void add() throws Exception {
Foo foo = new Foo();
foo.add("One", "Two", "Three");
Assertions.assertThat(foo.getElements())
.containsExactly("One", "Two", "Three");
}
AssertJ 的一个优点是不需要按预期声明 List:它使断言更直接,代码更易读:
Assertions.assertThat(foo.getElements())
.containsExactly("One", "Two", "Three");
但是断言/匹配器库是必须的,因为它们真的会更进一步。
现在假设 Foo 不存储 Strings 而是 Bars 实例。
这是一个非常普遍的需求。
使用 AssertJ,断言仍然很容易编写。更好的是,即使元素的类没有覆盖equals()/hashCode(),您也可以断言列表内容是相等的,而 JUnit 方式要求这样做:
import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;
@Test
void add() throws Exception {
Foo foo = new Foo();
foo.add(new Bar(1, "One"), new Bar(2, "Two"), new Bar(3, "Three"));
Assertions.assertThat(foo.getElements())
.extracting(Bar::getId, Bar::getName)
.containsExactly(tuple(1, "One"),
tuple(2, "Two"),
tuple(3, "Three"));
}