简体   繁体   中英

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

I am writing a JUnit test and I want to test that all the fields in 2 objects are equal.

I have tried the following:

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

But the test is failing, even though the fields in the 2 objects are the same.

They are both have: 100100 , sampleName and sampleAddress

The simplest/the most preferred way is to override equals() (and hashCode() ) in all the classes you assert on (including the nested classes) and use Assert.assertEquals(expected, actual) .

The reason why the comparison fails for 2 fields is because EqualsBuilder.reflectionEquals(Object lhs, Object rhs) is doing a shallow comparison and in your actual code Person has a reference to an Address instance, which does not have equals() implemented.

EqualsBuilder#reflectionEquals() has many variations. Consider to exclude the unwanted attributes. Then you can precisely compare 2 objects.

You can also use a simple equals() override in your particular class and do the same.

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...-

In your example, you need to override the equals method in your class Person (returning true if the attributes of the Person object are all equal). For example:

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;
    }

}

You can do it automatically with an IDE, the previous snippet was generated automatically with Eclipse.

在Person类中编写equals,hashCode方法来确定对象的相等性

Personally, I would use a custom matcher for this

@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");
        }
    };

}

You can use a nice library called Unitils which logs very nicely as well with a in depth info what went wrong

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

Easy to use and do not need to override the equals and hash methods. This assertion loops over all fields in both objects and compares their values using reflection. For the above example, it will first compare both id field values, next both first field values and finally both last fields values.

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

With Kotlin, you can use Mockito's matchers:

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

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

You can test using assertEquals instead of assertTrue

@Test
public void testPersonObjectsAreEqual(){

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

    Assert.assertEquals(expectedPerson, actualPersonReturned);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM