How do I assert equality on two classes without an equals method?

后端 未结 23 1349
臣服心动
臣服心动 2020-11-28 05:20

Say I have a class with no equals() method, to which do not have the source. I want to assert equality on two instances of that class.

I can do multiple asserts:

相关标签:
23条回答
  • 2020-11-28 05:59

    I stumbled on a very similar case.

    I wanted to compare on a test that an object had the same attribute values as another one, but methods like is(), refEq(), etc wouldn't work for reasons like my object having a null value in its id attribute.

    So this was the solution I found (well, a coworker found):

    import static org.apache.commons.lang.builder.CompareToBuilder.reflectionCompare;
    
    assertThat(reflectionCompare(expectedObject, actualObject, new String[]{"fields","to","be","excluded"}), is(0));
    

    If the value obtained from reflectionCompare is 0, it means they are equal. If it is -1 or 1, they differ on some attribute.

    0 讨论(0)
  • 2020-11-28 06:02

    Compare field-by-field:

    assertNotNull("Object 1 is null", obj1);
    assertNotNull("Object 2 is null", obj2);
    assertEquals("Field A differs", obj1.getFieldA(), obj2.getFieldA());
    assertEquals("Field B differs", obj1.getFieldB(), obj2.getFieldB());
    ...
    assertEquals("Objects are not equal.", obj1, obj2);
    
    0 讨论(0)
  • 2020-11-28 06:02

    Can you put the comparision code you posted into some static utility method?

    public static String findDifference(Type obj1, Type obj2) {
        String difference = "";
        if (obj1.getFieldA() == null && obj2.getFieldA() != null
                || !obj1.getFieldA().equals(obj2.getFieldA())) {
            difference += "Difference at field A:" + "obj1 - "
                    + obj1.getFieldA() + ", obj2 - " + obj2.getFieldA();
        }
        if (obj1.getFieldB() == null && obj2.getFieldB() != null
                || !obj1.getFieldB().equals(obj2.getFieldB())) {
            difference += "Difference at field B:" + "obj1 - "
                    + obj1.getFieldB() + ", obj2 - " + obj2.getFieldB();
            // (...)
        }
        return difference;
    }
    

    Than you can use this method in JUnit like this:

    assertEquals("Objects aren't equal", "", findDifferences(obj1, obj));

    which isn't clunky and gives you full information about differences, if they exist (through not exactly in normal form of assertEqual but you get all the info so it should be good).

    0 讨论(0)
  • 2020-11-28 06:04

    As an alternative for junit-only, you can set fields to null prior to equals assertion:

        actual.setCreatedDate(null); // excludes date assertion
        expected.setCreatedDate(null);
    
        assertEquals(expected, actual);
    
    0 讨论(0)
  • 2020-11-28 06:05

    This is a generic compare method , that compares two objects of a same class for its values of it fields(keep in mind those are accessible by get method)

    public static <T> void compare(T a, T b) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        AssertionError error = null;
        Class A = a.getClass();
        Class B = a.getClass();
        for (Method mA : A.getDeclaredMethods()) {
            if (mA.getName().startsWith("get")) {
                Method mB = B.getMethod(mA.getName(),null );
                try {
                    Assert.assertEquals("Not Matched = ",mA.invoke(a),mB.invoke(b));
                }catch (AssertionError e){
                    if(error==null){
                        error = new AssertionError(e);
                    }
                    else {
                        error.addSuppressed(e);
                    }
                }
            }
        }
        if(error!=null){
            throw error ;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 06:06

    From your comments to other answers, I don't understand what you want.

    Just for the sake of discussion, lets say that the the class did override the equals method.

    So your UT will look something like:

    SomeType expected = // bla
    SomeType actual = // bli
    
    Assert.assertEquals(expected, actual). 
    

    And you are done. Moreover, you can not get the "full equality picture" if the assertion fails.

    From what I understand, you are saying that even if the type did override equals, you would not be interested in it, since you want to get the "full equality picture". So there is no point in extending and overriding equals either.

    So you have to options: either compare property by property, using reflection or hard-coded checks, I would suggest the latter. Or: compare human readable representations of these objects.

    For example, you can create a helper class that serializes the type you wish tocompare to an XML document and than compare the resulting XML! in this case, you can visually see what exactly is equal and what is not.

    This approach will give you the opportunity to look at the full picture but it is also relatively cumbersome (and a little error prone at first).

    0 讨论(0)
提交回复
热议问题