Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I compare POJOs by their fields reflectively

I am basically looking for a unit testing framework, which I can use to compare POJOs which don't override equals and hascode methods. I had a look at JUnit, Test NG and Mockito but they don't seem to solve the purpose.

For example consider the code below :

public class CarBean { 

    private String brand;
    private String color;

    public CarBean (){
    }

    public CarBean (String brand, String color){
        this.brand= brand;
        this.color= color;
    }

    /**
     * @return the brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * @param the brand to set
     */
    public void setBrand(String brand) {
        this.brand= brand;
    }

    /**
     * @return the color
     */
    public String getColor() {
        return color;
    }

    /**
     * @param the color to set
     */
    public void setColor(String color) {
        this.color= color;
    }
}

The POJO CarBean represents a real world car. It has two parameters, brand and color. Now, suppose you have two car objects as below :

CarBean car1 = new CarBean("Ford","Black");
CarBean car2 = new CarBean("Ford","Black");

Both the objects have same parameter values. But when you compare this using equals, it returns false :

car1.equals(car2); // This returns false

Now I need to unit test a method that returns CarBean object. In this scenario I would either need to compare the carbean attributes one by one or I would need to implement equals() and hashcode() methods.

So my question is - Is there already a unit testing framework which can handle this ?

like image 308
Crickcoder Avatar asked Dec 05 '14 23:12

Crickcoder


3 Answers

This type of reflection is built into Hamcrest as SamePropertyValuesAs, which compares bean-named properties (getFoo, isBar) instead of the fields that likely power them. Core Hamcrest support is built into JUnit, so you'd just need to add the Hamcrest library that includes the SamePropertyValuesAs matcher.

assertThat(car1, samePropertyValuesAs(car2));
like image 55
Jeff Bowman Avatar answered Oct 22 '22 06:10

Jeff Bowman


Override the toString() method in your pojo class like below

@Override
public String toString() {
    return "brand: " + this.brand + ",color: " + this.color;
}


car1.toString().equals(car2.toString()); //It will return true if both objects has same values

In case you have large nos of parameter i will suggest you to go with bellow code

public static boolean comparePOJO(Object obj1, Object obj2) {
    return new Gson().toJson(obj1).equals(new Gson().toJson(obj2));
}
comparePOJO(car1,car2); //It will return true
like image 6
Deepesh kumar Gupta Avatar answered Oct 22 '22 04:10

Deepesh kumar Gupta


Unitils seems to do solve the purpose for me. The following APIs can compare objects reflectively. It can compare even if the attributes of a POJO themselves are user defined POJOs :

import static org.unitils.reflectionassert.ReflectionAssert.*;

// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")), 
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"));

// Ignore Null / 0 values in the expected object
assertReflectionEquals(new Person("John", null, new Address("New street", 0, null)),
                                 new Person("John", "Doe", new Address("New street", 5, "Brussels"), 
                                 ReflectionComparatorMode.IGNORE_DEFAULTS); 

// Ignore collection order
assertReflectionEquals(Arrays.asList(new Person("John"), new Person("Jane")),
                                 new Person[] {new Person("Jane"), new Person("John")}, 
                                 ReflectionComparatorMode.LENIENT_ORDER);

// Ignore null/0 values + collection order
assertLenientEquals(Arrays.asList(new Person("John"), null),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

// Check only the firstName property 
assertPropertyLenientEquals("firstName", Arrays.asList("John", "Jane"),
                                 new Person[] {new Person("Jane", "Doe"), new Person("John", "Doe")});

Further information at Unitils Cookbook

like image 5
Crickcoder Avatar answered Oct 22 '22 05:10

Crickcoder