У меня есть простой класс 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 обладает богатой стандартной библиотекой, включая коллекции, ввод/вывод, сетевые операции и многое другое.
вы можете попробовать перехватить исключение 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
и выяснить, какие свойства или ключи ) является несоответствием.
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);
}
}
@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));
}
}
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();
}