Friday, 15 April 2016

Meanbean: How to test equals method

EqualsMethodTester class provides testEqualsMethod method to test the equals method. Mean bean applies several algorithms on equals method to verify that equals method is correct.

As per Java doc, equals method should satisfy following conditions.

a.   It is reflexive: for any non-null reference value x, x.equals(x) should return true.
b.   It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
c.    It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
d.   It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
e.   For any non-null reference value x, x.equals(null) should return false.

Mean bean applies following algorithms to test above conditions.

Algorithm
Description
Reflexive Test Algorithm
Checks the reflexive property of object equals method.

Create instance of class under test, object x.
assert x.equals(x)
Symmetric Test Algorithm
Checks the symmetric property of object equals method.

Create instance of class under test, object x
Create instance of class under test, object y
assert x.equals(y)
assert y.equals(x)
Transitive Test Algorithm
Checks the transitive property of object equals method.

create instance of class under test, object x
create instance of class under test, object y
create instance of class under test, object z
assert x.equals(y)
assert y.equals(z)
assert x.equals(z)
Consistent Test Algorithm
Check consistency property of object equals method on multiple invocations.

create instance of class under test, object x
create instance of class under test, object y
for j in 1..100 do
         assert x.equals(y)
         assert result is consistent
end for
Nullity Test Algorithm
create instance of class under test, object x
assert x.equals(null) is false
Property significance Test Algorithm
for each property in public getter/setter method pairs do
         create instance of class under test, object x
         create instance of class under test, object y
         change property of y to contain a different value
         if property is insignificant then
                  assert x.equals(y)
         else
                  assert x.equals(y) is false
         end if
end for

In addition to this, it applies ‘different types test algorithm’.

create instance of class under test, object x
create object y of a different type to x
assert x.equals(y) is false

Following snippet checks the equals method of Employee class.

EqualsMethodTester tester = new EqualsMethodTester();
tester.testEqualsMethod(Employee.class);


Employee.java

public class Employee {
  private String firstName;
  private String lastName;
  private int id;
  private int age;
  private float salary;

  public String getFirstName() {
    return firstName.toUpperCase();
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName.toUpperCase();
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public float getSalary() {
    return salary;
  }

  public void setSalary(float salary) {
    this.salary = salary;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result
        + ((firstName == null) ? 0 : firstName.hashCode());
    result = prime * result + id;
    result = prime * result
        + ((lastName == null) ? 0 : lastName.hashCode());
    result = prime * result + Float.floatToIntBits(salary);
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Employee other = (Employee) obj;
    if (age != other.age)
      return false;
    if (firstName == null) {
      if (other.firstName != null)
        return false;
    } else if (!firstName.equals(other.firstName))
      return false;
    if (id != other.id)
      return false;
    if (lastName == null) {
      if (other.lastName != null)
        return false;
    } else if (!lastName.equals(other.lastName))
      return false;
    if (Float.floatToIntBits(salary) != Float.floatToIntBits(other.salary))
      return false;
    return true;
  }

}


TestBean.java

import org.junit.Test;
import org.meanbean.test.EqualsMethodTester;

public class TestBean {

  @Test
  public void testEmployee() {
    EqualsMethodTester tester = new EqualsMethodTester();
    tester.testEqualsMethod(Employee.class);
  }
}


‘testEqualsMethod’ method is available in following overloaded forms.

public void testEqualsMethod(Class<?> clazz, String... insignificantProperties)

public void testEqualsMethod(Class<?> clazz, Configuration customConfiguration, String... insignificantProperties)

public void testEqualsMethod(EquivalentFactory<?> factory, String... insignificantProperties)

public void testEqualsMethod(EquivalentFactory<?> factory, Configuration customConfiguration,String... insignificantProperties)

insignificantProperties  specifies the names of properties that are not used when deciding whether objects are logically equivalent.

An EquivalentFactory creates non-null logically equivalent objects that will be used to test whether the equals logic implemented by the type is correct.

testEqualsMethod using EquivalentFactory

import org.junit.Test;
import org.meanbean.lang.EquivalentFactory;
import org.meanbean.test.EqualsMethodTester;

public class TestBean {

  @Test
  public void testEmployee() {
    EqualsMethodTester tester = new EqualsMethodTester();
    tester.testEqualsMethod(new EmployeeFactory());
  }
  
  public class EmployeeFactory implements EquivalentFactory<Employee>{

    public Employee create() {
      Employee emp = new Employee();
      
      emp.setAge(26);
      emp.setFirstName("sudhir");
      emp.setId(1234);
      emp.setLastName("Sami");
      emp.setSalary(1234567);
      return emp;
    }
    
  }
}




Previous                                                 Next                                                 Home

No comments:

Post a Comment