Assert.assertEquals在两个列表中

时间:2015-11-06 09:44:13

标签: java junit junit4 junit3

我有一个班级MySchool

public class MySchool{
    private long timestamp;
    private SchoolEvent event;
    private Object value;

    //getter & setters
    ...

    @Override
    public String toString() {
        return "MySchool [timestamp=" + timestamp + ", event="
                + event + ", value=" + value + "]";
    }
}

SchoolEvent是枚举类型:

public static enum SchoolEvent {
        CEREMONY, HOLIDAY
    }

我尝试使用Assert.assertEquals()来比较两个学校列表:

List<MySchool> schoolList1 = generateSchools();
List<MySchool> schoolList2 = readSchoolsFromFile();

Assert.assertEquals(schoolList1, schoolList2);

失败并出现以下错误:

expected: java.util.ArrayList<[MySchool [timestamp=0, event=CEREMONY, value=null], MySchool [timestamp=0, event=HOLIDAY, value=null]]> 

but was:  java.util.ArrayList<[MySchool [timestamp=0, event=CEREMONY, value=null], MySchool [timestamp=0, event=HOLIDAY, value=null]]>

我不明白为什么错误听起来不像是错误,我只是检查错误信息,两个列表中每个元素对象的每个字段都是euqal。

我还检查了关于List#equal的Java文档,它还说:

  

如果两个列表包含相同的元素,则它们被定义为相等   以相同的顺序。

为什么assertEquals()失败呢?

4 个答案:

答案 0 :(得分:2)

  

我不明白为什么错误听起来不像是错误,我只是检查错误信息,两个列表中每个元素对象的每个字段都是euqal。

是的,但这并不意味着对象被认为是平等的。

您需要覆盖equals()(和hashCode())才能使不同的对象被视为相等。默认情况下,equals方法只检查对象身份 ...换句话说,x.equals(y)相当于检查xy默认情况下,请参阅完全相同的对象。如果您想要不同的行为 - 以便检查某些字段是否相等 - 那么您需要在equals()中指定该行为,并以与此一致的方式实现hashCode()

请注意,此问题完全不依赖于集合。如果比较单个对象,你会遇到同样的问题:

MySchool school1 = schoolList1.get(0);
MySchool school2 = schoolList2.get(0);
Assert.areEqual(school1, school2); // This will fail...

答案 1 :(得分:1)

您的班级必须实施equals()。我将在下面添加一个示例实现:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    MySchool mySchool = (MySchool) o;

    if (timestamp != mySchool.timestamp) return false;
    if (event != mySchool.event) return false;
    return !(value != null ? !value.equals(mySchool.value) : mySchool.value != null);

}

然后我会使用hamcrest在集合上断言:

public void testTwoEventsAreEquals() throws Exception {
    List<MySchool> schoolList1 = Arrays.asList(new MySchool(SchoolEvent.CEREMONY), new MySchool(SchoolEvent.HOLIDAY));
    List<MySchool> schoolList2 = Arrays.asList(new MySchool(SchoolEvent.CEREMONY), new MySchool(SchoolEvent.HOLIDAY));

    assertThat(schoolList1, containsInAnyOrder(schoolList2.toArray()));
}

如果你正在使用maven,你必须添加Hamcrest作为依赖项,以便上面的代码编译。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
</dependency>

答案 2 :(得分:1)

不要按照别人的建议放置equals方法(抱歉,伙计们)。这将是一个生产中的测试代码,它本身不仅是错误的,而且如果您向该类添加另一个字段但忘记更新equals方法会怎么样?您的测试不会测试您认为他们正在测试的内容。如果equals方法错了怎么办?如果它总是返回真实怎么办?你的测试总是绿色的,你会错误地确信一切都很好。因为当然谁会为equals方法编写测试。

我强烈建议您使用shazamcrest等工具。这允许您只需编写assertThat(actual, sameBeanAs(expected)),而不必担心任何事情。它不需要对您的生产代码进行任何更改。它将覆盖所有字段,无论其访问修饰符如何。还提供非常好的诊断。它会抛出ComparisonFailure(而不是AssertionError),IDE将为您提供很好的并排比较。

代码:

List<MySchool> schoolList1 = generateSchools();
List<MySchool> schoolList2 = readSchoolsFromFile();

assertThat(schoolList2, sameBeanAs(schoolList2));

需要依赖性:

<dependency>
    <groupId>com.shazam</groupId>
    <artifactId>shazamcrest</artifactId>
    <version>0.11</version>
</dependency>

您获得的诊断:

Comparison Failure diagnostics

注意:

请务必使用com.shazam.shazamcrest.MatcherAssert.assertThat,而不是hamcrestjunit。它的工作方式与其他assertThat方法完全相同,但如果与sameBeanAs一起使用,则会抛出ComparisonFailure,而不是AssertionError

答案 3 :(得分:0)

要使两个对象相等,它们的equals()方法必须返回true。

如果两个对象都是SAME对象,则equals()的默认实现仅返回true,但如果它们是具有相同“内容”的不同对象则不返回。

所以,x.equals(y);可以true,即使x == y(“x和y是同一个对象”)是false,如果是equals()对于参数y,x方法返回true