如何使用 reflectionEquals 检查 2 个对象中的所有字段是否相等?

How to check all fields in 2 objects are equal using reflectionEquals?

我正在编写一个 JUnit 测试,我想测试 2 个对象中的所有字段 是否相等。

我试过以下方法:

    @Test
    public void testPersonObjectsAreEqual(){
      
        Person expectedPerson = new Person("100100", "sampleName", "sampleAddress");
        Person actualPersonReturned = repository.getPersonById("100100");
        
        Assert.assertTrue(EqualsBuilder.reflectionEquals(expectedPerson, actualPersonReturned));
    }

但是测试失败了,即使 2 个对象中的字段相同。

他们都有:100100sampleNamesampleAddress

simplest/the 最首选的方法是在您断言的所有 类 中覆盖 equals()(和 hashCode())(包括嵌套的 类 ) 并使用 Assert.assertEquals(expected, actual).

2 个字段的比较失败的原因是因为 EqualsBuilder.reflectionEquals(Object lhs, Object rhs) 正在进行浅比较,并且在您的实际代码中 Person 引用了一个 Address 实例,它确实尚未 equals() 实施。

在Person中写equals,hashCode方法class判断对象是否相等

您可以使用 assertEquals 而不是 assertTrue 进行测试

@Test
public void testPersonObjectsAreEqual(){

    Person expectedPerson = new Person("100100", "sampleName", "sampleAddress")
    Person actualPersonReturned = repository.getPersonById("100100);

    Assert.assertEquals(expectedPerson, actualPersonReturned);
}

EqualsBuilder#reflectionEquals() 有很多变化。 考虑排除不需要的属性。然后你可以精确比较2个对象。

您也可以在您的特定 class 中使用简单的 equals() 覆盖并执行相同的操作。

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/EqualsBuilder.html#reflectionEquals-java.lang.Object-java.lang.Object-java.lang.String...-

在您的示例中,您需要覆盖 class Person 中的 equals 方法(如果 Person 对象的属性都相等则返回 true)。例如:

public class Person {

    private String name;
    private String surname;

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (surname == null) {
            if (other.surname != null)
                return false;
        } else if (!surname.equals(other.surname))
            return false;
        return true;
    }

}

您可以使用 IDE 自动完成,前面的代码片段是使用 Eclipse 自动生成的。

就个人而言,我会为此使用自定义匹配器

@Test
public void testPersonObjectsAreEqual(){

    Person expectedPerson = new Person("100100", "sampleName", "sampleAddress")
    Person actualPersonReturned = repository.getPersonById("100100");

    assertThat(actualPersonReturned, is(matchingPerson(expectedPerson)));
}

private Matcher<Person> matchingPerson(Person expected) {
    return new TypeSafeMatcher<Person>() {
        public boolean matchesSafely(Person actual) {
            return actual.getId().equals(expected.getId())
                && actual.getName().equals(expected.getName();
                && actual.getAddress().equals(expected.getAddress();
        }

        public void describeMismatchSafely(Person person, Description mismatchDescription) {
            mismatchDescription.appendText("give a meaningful message");
        }
    };

}

您可以使用一个名为 Unitils 的不错的库,它可以很好地记录错误并提供详细信息

User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);

易于使用,不需要覆盖 equals 和 hash 方法。 此断言遍历两个对象中的所有字段并使用反射比较它们的值。对于上面的示例,它将首先比较两个 id 字段值,然后比较第一个字段值,最后比较两个最后字段值。

http://www.unitils.org/tutorial-reflectionassert.html

对于 Kotlin,您可以使用 Mockito 的匹配器:

@Test
fun someEqualsTest(){
 
    val actual = ...
    val expected = ...

    assertTrue(ReflectionEquals(actual).matches(expected))
}