compare objects in Java?

1

I'm using Java 8, Netbeans 8.2 and JUnit 4.12.

I have two instances of a class that I want to compare to know if they are "equal", where their properties have the same values. That is, if they have id and name, if I write in the test:

assertEquals(instanceA.getId(), instanceB.getId( ));
assertEquals(instanceA.getName(), instanceB.getName( ));

OK, but if I add a third assert by comparing them directly:

assertEquals(instanceA, instanceB);

or

assertTrue(instanceA.equals(instanceB));

this fails. I think because although they keep the same thing they are different instances (they point to different memory addresses). Can someone clarify it? Thanks.

  

Edited

The question suggested as "duplicate" focuses on comparing the value of two Strings and all the answers go in this direction, except this one: link that makes a comparison of objects, ignoring this answer, all other solutions fail. My question refers to how to compare objects according to the value of their properties and specifically in order to implement unit tests. I think that by looking at both questions and their answers you can see similarities but it is clear that they are two different questions.

Maybe he does not explain me correctly. If someone is unclear, is it the same question as it has a completely different solution?

Compare two strings:

String a = "hola";
String b = "hola";
boolean res = a.equals(b);
System.out.println("Comparando strings: " + res); 
// Comparando strings: true

Compare two objects:

class Foo {
    private int id;
    private String name;

    public Foo(int id, String name) {
        this.id = id;
        this.name = name;
    }

} // class

Foo a = new Foo(1, "hola");
Foo b = new Foo(1, "hola");
boolean res = a.equals(b);
System.out.println("Comparando objetos: " + res); 
// Comparando objetos: false

What happened? Well that's what I was basically asking ...

    
asked by Orici 18.07.2018 в 15:54
source

3 answers

4

The equals method of Object is simply a comparison

public boolean equals(Object obj) {
    return (this == obj);
}

So if you want them to be the same (even pointing to different memory location) you must overwrite the equals method and if that object you will use it in some Collection with hash, it overwrites the hashCode once

In case it is impossible to edit the class because it is a Legacy class, do not have the source or else there is the test library

Dependency in Maven

<dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-core</artifactId>
    <version>3.4.2</version>
    <scope>test</scope>
</dependency>

and change in your code of

assertEquals(instanceA, instanceB);

a

assertReflectionEquals(instanceA, instanceB);

The documentation and explanation comes on its official website link

    
answered by 18.07.2018 в 15:59
1

You have to overwrite the method

  

equals (Object obj)

There you can compare the attributes you deem necessary to determine that two objects are equal.

What Java does by default is to compare the reference to determine if two objects are equal.

Take a look in the documentation to see the properties that your equals method has to cover.

link

    
answered by 18.07.2018 в 16:12
0

An alternative to not touching the code of project classes and being able to use JUnit without having to do multiple asserts is overwrite the equals () method within a new class , created only for the tests.

I create a class XxxMock that extends the class Xxx to test and placed it next to the classes with the tests, in this class XxxMock only the necessary constructors and the equals () method overwritten are added.

So to test the next class:

public class Foo {

    private String id;
    private String name;
    private int age;


    public Foo(String id, String name, int age) {
        this.id   = id;
        this.name = name;
        this.age  = age;
    }

    // Setters and Getters
    // ...

} // class

Before I needed an assert to check each of the properties:

assertEquals(expResult.getId(),   result.getId( ));
assertEquals(expResult.getName(), result.getName( ));
assertEquals(expResult.getDescription(), result.getDescription( ));

Now, I create the following class and placed it with the classes that contain the tests:

public class FooMock extends Foo {

    public FooMock(String id, String name, int age) {
        super(id, name, age);
    }


    /**
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }

        Foo foo = (Foo) obj;

        return (
            ((this.getId() == null && foo.getId() == null) ||
                this.getId().equals(foo.getId( ))) &&
            ((this.getName() == null && foo.getName() == null) ||
                this.getName().equals(foo.getName( ))) &&
            this.getAge() == foo.getAge( ));
    }

} // class

Now "expResult" should be an instance of FooMock instead of one of Foo and will only need an assert :

assertTrue(expResult.equals(result));
  

Edited:

It checks if obj is null within equals () .

    
answered by 19.07.2018 в 12:06