mardi 6 octobre 2015

Testing an overriden equals method

I'm reading J. Bloch's effective Java and needed to brush up the equals/hashCode contracts and relationships.

I have the following JavaBeans class:

public class MyJavaBean{

    private int id;

    private Properties fItem;  //Enumeration type

    private String value;

    private Rule rule;         //Enumeration type

    private int fId;

    //GET, SET

        @Override
    public boolean equals(Object o){
        if(!(o instanceof MyJavaBean))
            return false;
        MyJavaBeanv = (MyJavaBean) o;
        return (fItem == null ? v.fItem == null : fItem.equals(v.fItem)) && 
                (value == null ? v.value == null : value.equals(v.value)) && 
                (rule == null ? v.rule == null : rule.equals(v.rule)) && 
                fId == v.fId && id == v.id;
    }

    @Override 
    public int hashCode(){
        int result = 17;
        if(fItem != null)
            result = 31 * result + fItem.hashCode();
        if(value != null)
            result = 31 * result +  value.hashCode();
        if(rule != null)
            result = 31 * result + rule.hashCode();
        result = 31 * result + fId;
        result = 31 * result + id;
        return result;
    }
}

He also suggest we write unitTests to make sure the contracts are actually satisfied. Here is what he said(italic-bold emphasize mine):

When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent? And don’t just ask yourself; write unit tests to check that these properties hold!

So, I can't imagine how to write unit test for that pretty straightforward case. Well, I'd write something like that:

public class MyTest{

    //Each pair consists of the equals object
    private Map<MyJavaBean, MyJavaBean> equalValueMap;

    @Before
    public void init(){
        //initializing the map, using ThredLocalRandom 
        //to get ints and enums randomly
    }

    @Test
    public void testReflexive(){
        for(MyJavaBean fiv: equalValueMap.keySet()){
            Assert.assertEquals(fiv.equals(fiv), true);
        }
    }

    @Test
    public void testSymmetric(){
        for(MyJavaBean fiv: equalValueMap.keySet()){
            Assert.assertEquals(equalValueMap.get(fiv).equals(fiv), true);
            Assert.assertEquals(fiv.equals(equalValueMap.get(fiv)), true);
        }
    }

    @Test
    public void testHashCode(){
        for(FilterItemValue fiv: equalFilterValueMap.keySet()){
            Assert.assertEquals(equalFilterValueMap.get(fiv).hashCode(), fiv.hashCode());
        }
    }
}

But I think such tests just waste the build-time, because of their simplicity. Is it worthy to write tests for the methods for simple JavaBeans?

Aucun commentaire:

Enregistrer un commentaire