Как получить, какое свойство объекта первым не соответствует в JUnit assertEquals?

У меня есть простой класс pojo в формате, показанном ниже.

class PojoClass {

    property1;
    ...
    propertyN;

    @override
    public int hashcode() {
        //implementation
    }

    @override
    public boolean equals(Object o) {
        //implementation
    }

    @override
    public String toString)() {
        return "PojoClass[property1= " + property1 ... propertyN + "]";
    }

}

В моем тестовом случае я делаю то, что мне нужно, и у меня есть ожидаемый объект PojoClass и фактический объект PojoClass. В некоторых случаях даже массивы (ожидаемые и фактические) объектов PojoClass. Когда assert терпит неудачу, я получаю сообщение, которое печатает toString ожидаемого и фактического.

toString в данном случае недостаточно удобен, так как мой PojoClass объект содержит от 20 до 30 свойств. Мне приходится вручную проверять все свойства, если они совпадают или нет. Есть ли способ в JUnit напрямую указать, не соответствует ли свойство ожидаемого объекта свойству фактического объекта?

🤔 А знаете ли вы, что...
Java обладает богатой стандартной библиотекой, включая коллекции, ввод/вывод, сетевые операции и многое другое.


592
3

Ответы:

вы можете попробовать перехватить исключение ComparisonFailure, как показано ниже
P.S. Запускайте одно утверждение за раз, т.е. комментируйте другое, чтобы увидеть, какое исключение поймано.

@org.junit.Test
public void someSimpleTest() {
    try {
        Assert.assertEquals("123", "456");//Throw ComparisonFailure 
        Assert.assertArrayEquals(new String[] {"ABC","efg"}, new String[] {"ABCe","xys"});//Throw ArrayComparisonFailure 
    } catch(ComparisonFailure e) {
        System.out.println("Inside block");
        System.out.println(e);
    } catch(ArrayComparisonFailure e) {
        System.out.println("Inside block");
        System.out.println(e);
    }
}

в этом примере, если я прокомментирую seertEquals и выполню assertArrayEquals, он четко напечатает оператор

arrays first differed at element [0]; expected:<ABC[]> but was:<ABC[e]>

Следовательно, чтобы ответить на ваш вопрос, есть ли в JUnit какой-либо способ напрямую указать, не соответствует ли какое свойство ожидаемого объекта свойству фактического объекта?

Это ясно говорит о том, что первый элемент не равен, следовательно, это не удалось.

Точно так же вы можете проверить свои различия toString.

http://junit.sourceforge.net/javadoc/org/junit/ComparisonFailure.html

Обновление для пользовательского объекта Этот код будет печатать только разницу между toString объекта

class PojoClass {

    String prop1;
    int prop2;
    String prop3;

    public  PojoClass(String prop1, int prop2, String prop3) {
        this.prop1 = prop1;
        this.prop2 = prop2;
        this.prop3 = prop3;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PojoClass other = (PojoClass) obj;
        if (prop1 == null) {
            if (other.prop1 != null)
                return false;
        } else if (!prop1.equals(other.prop1))
            return false;
        if (prop2 != other.prop2)
            return false;
        if (prop3 == null) {
            if (other.prop3 != null)
                return false;
        } else if (!prop3.equals(other.prop3))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "PojoClass [prop1 = " + prop1 + ", prop2 = " + prop2 + ", prop3 = " + prop3 + "]";
    }

Junit для печати разницы ошибок утверждения

@org.junit.Test
    public void someSimpleTest() {
        try {   
            PojoClass class1 = new PojoClass("Sample", 1, "foo");
            PojoClass class2 = new PojoClass("Sample1", 1, "foo2");
            Assert.assertEquals(class1, class2);
        } catch(AssertionError e) {
            getStringDiff(e);
        }
    }

    private void getStringDiff(AssertionError e) {
        String msg = e.getMessage();
        String str1 = msg.substring(msg.indexOf("<"), msg.indexOf(">")+1);
        String str2 = msg.substring(msg.lastIndexOf("<"), msg.lastIndexOf(">")+1);
        System.out.println(StringUtils.difference(str1, str2));
    }

Я считаю, что в jUnit такой функции нет.

Метод assertEquals в конечном итоге вернет expected.equals(actual), возможно, вы можете изменить свою реализацию метода equals таким образом, чтобы он регистрировал, какие свойства, если таковые имеются, не совпадают, что приводит к тому, что метод equals возвращает false.


Решено

Решение с использованием Gson. Основная идея этого решения состоит в том, чтобы получить значения объектов из toString и десериализовать их в Json, а затем использовать метод Maps.difference в библиотеке Gson для сравнения двух Json и выяснить, какие свойства или ключи ) является несоответствием.

  1. Обновите Pojo до строки, чтобы вернуть строковый json этого конкретный объект POJO
class PojoClass {

    property1;
    ...
    propertyN;

    @override
    public int hashcode() {
        //implementation
    }

    @override
    public boolean equals(Object o) {
        //implementation
    }

    @override
    public String toString)() {
        return new Gson().toJson(this);
    }

}
  1. Тестовый пример должен выглядеть так, как указал Аид.
@Test
public void pojoClassTest() throws Exception {
    List<PojoClass> sourcePojoList = getSourcePojoList();
    List<PojoClass> targetPojoList = getTargetPojoList();
    try {
        Assert.assertArrayEquals(sourcePojoList.toArray(), targetPojoList.toArray());
    }
    catch (ArrayComparisonFailure e) {
        Assert.fail(getMessage(e));
    }
}
  1. Метод getMessage — это когда мы получаем существующее сообщение от JUnit, создаем два Json и сравниваем их. См. пост это для метода сравнения.
// The junit error message will be in following format
// java.lang.AssertionError: arrays first differed at element [0]; expected:<{json}> but was:<{json}>
// So we get both source and target Json, and throw in the magic of gson library
// We compare them using method mentioned in link above.
// Now the new message that will be asserted contains message like below (assuming property 1 of the object is the mismatch)
// not equal: value differences = {property1=("expected","actual")}

private static String getMessage(AssertionError e) throws IOException {
    String msg = e.getMessage();
    String sourceJson = msg.substring(msg.indexOf("expected:<") + 10, msg.indexOf("> but was:"));
    String targetJson = msg.substring(msg.lastIndexOf("but was:<") + 9, msg.lastIndexOf(">"));
    Gson g = new Gson();
    Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
    Map<String, Object> firstMap = g.fromJson(sourceJson, mapType);
    Map<String, Object> secondMap = g.fromJson(targetJson, mapType);
    return Maps.difference(firstMap, secondMap).toString();
}