Скажем, у меня есть класс без метода equals (), для которого нет источника. Я хочу подтвердить равенство двух экземпляров этого класса.
Я могу сделать несколько утверждений:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
Мне не нравится это решение, потому что я не получаю полной картины равенства, если раннее утверждение терпит неудачу.
Я могу вручную сравнить и отследить результат:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
Это дает мне полную картину равенства, но неуклюже (и я даже не учел возможные нулевые проблемы). Третий вариант - использовать Comparator, но compareTo () не сообщает мне, для каких полей не удалось выполнить равенство.
Есть ли лучший способ получить то, что я хочу от объекта, без подкласса и переопределения равенства (тьфу)?
java
unit-testing
junit
Райан Нельсон
источник
источник
equal
метода только сообщает, равны ли два экземпляра, и нам все равно, почему значения не равны.Object
естьequals
метод, вы, вероятно, имели в виду отсутствие переопределенного метода равенства.Ответы:
Mockito предлагает сопоставление отражений:
Для последней версии Mockito используйте:
Для более старых версий используйте:
источник
org.mockito.internal.matchers.apachecommons
. В документах Mockito указано:org.mockito.internal
-> «Внутренние классы, не используемые клиентами». Используя это, вы подвергнете свой проект риску. Это может измениться в любой версии Mockito. Читайте здесь: site.mockito.org/mockito/docs/current/overview-summary.htmlMockito.refEq()
Вместо этого используйте .Mockito.refEq()
терпит неудачу, если у объектов нет id set = (refEq
не работает для сравнения, поскольку метод хэш-кода не может сравнивать объекты.Здесь много правильных ответов, но я бы тоже хотел добавить свою версию. Это основано на Assertj.
ОБНОВЛЕНИЕ: в assertj v3.13.2 этот метод устарел, как указал Вудз в комментарии. Текущая рекомендация
источник
usingRecursiveComparison()
сisEqualTo()
, так что строка будетassertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
Обычно я реализую этот вариант использования с помощью org.apache.commons.lang3.builder.EqualsBuilder.
источник
Я знаю, что он немного староват, но надеюсь, что это поможет.
Я столкнулся с той же проблемой, что и вы, поэтому после расследования я нашел несколько вопросов, похожих на этот, и, найдя решение, я отвечаю на них так же, поскольку думал, что это может помочь другим.
Ответ на этот аналогичный вопрос , получивший наибольшее количество голосов (а не выбранный автором) , является для вас наиболее подходящим решением.
По сути, он заключается в использовании библиотеки Unitils .
Это использование:
Что пройдет, даже если класс
User
не будет реализованequals()
. Вы можете увидеть больше примеров и действительно классное утверждение, названноеassertLenientEquals
в их учебнике .источник
Unitils
похоже, он умер, см. Stackoverflow.com/questions/34658067/is-unitils-project-alive .Вы можете использовать Apache commons lang ReflectionToStringBuilder
Вы можете указать атрибуты, которые хотите протестировать, один за другим, или, лучше, исключить те, которые вам не нужны:
Затем вы сравниваете две строки как обычно. Что касается медленного отражения, я предполагаю, что это только для тестирования, поэтому не должно быть так важно.
источник
Если вы используете hamcrest для своих утверждений (assertThat) и не хотите использовать дополнительные тестовые библиотеки, то вы можете использовать его
SamePropertyValuesAs.samePropertyValuesAs
для утверждения элементов, у которых нет переопределенного метода равенства.Положительным моментом является то, что вам не нужно использовать еще одну тестовую среду, и она выдаст полезную ошибку, когда assert не работает (
expected: field=<value> but was field=<something else>
), а неexpected: true but was false
если вы используете что-то вродеEqualsBuilder.reflectionEquals()
.Обратной стороной является то, что это неглубокое сравнение и нет возможности для исключения полей (как в EqualsBuilder), поэтому вам придется работать с вложенными объектами (например, удалять их и сравнивать их независимо).
Лучший случай:
Уродливый случай:
Итак, выберите свой яд. Дополнительная структура (например, Unitils), бесполезная ошибка (например, EqualsBuilder) или неглубокое сравнение (hamcrest).
источник
Библиотека Hamcrest 1.3 Utility Matchers имеет специальный сопоставитель, который использует отражение вместо равенства.
источник
Некоторые методы сравнения отражений неглубокие
Другой вариант - преобразовать объект в json и сравнить строки.
источник
Используя Shazamcrest , вы можете:
источник
reflectEquals
возвращается,false
когда объекты имеют разные ссылки.Сравните поле за полем:
источник
Утверждения AssertJ могут использоваться для сравнения значений без
#equals
правильного переопределения метода, например:источник
Поскольку это старый вопрос, я предложу другой современный подход с использованием JUnit 5.
В JUnit 5 есть вызываемый метод,
Assertions.assertAll()
который позволит вам сгруппировать все утверждения в вашем тесте вместе, и он будет выполнять каждое из них и выводить все неудачные утверждения в конце. Это означает, что любые утверждения, которые терпят неудачу первыми, не остановят выполнение последних утверждений.источник
Вы можете использовать отражение, чтобы «автоматизировать» полное тестирование на равенство. вы можете реализовать код отслеживания равенства, который вы написали для одного поля, а затем использовать отражение для запуска этого теста для всех полей в объекте.
источник
Это общий метод сравнения, который сравнивает два объекта одного класса на предмет значений его полей (имейте в виду, что они доступны с помощью метода get)
источник
Я наткнулся на очень похожий случай.
Я хотел сравнить в тесте, что объект имеет те же значения атрибутов, что и другой, но такие методы, как
is()
,refEq()
и т. Д., Не будут работать по таким причинам, как мой объект, имеющий нулевое значение в своемid
атрибуте.Итак, это было решение, которое я нашел (ну, коллега нашел):
Если полученное значение
reflectionCompare
равно 0, это означает, что они равны. Если это -1 или 1, они различаются по какому-либо атрибуту.источник
В общем случае с AssertJ вы можете создать собственную стратегию компаратора:
Использование пользовательской стратегии сравнения в утверждениях
Примеры AssertJ
источник
Та же самая загадка возникла при модульном тестировании приложения для Android, и самым простым решением, которое я придумал, было просто использовать Gson для преобразования моих фактических и ожидаемых объектов значений в
json
и сравнения их как строк.Преимущество этого по сравнению с ручным сравнением поля за полем заключается в том, что вы сравниваете все свои поля, поэтому даже если вы позже добавите новое поле в свой класс, оно будет автоматически протестировано, по сравнению с тем, если бы вы использовали кучу
assertEquals()
на все поля, которые затем необходимо будет обновить, если вы добавите дополнительные поля в свой класс.jUnit также отображает строки для вас, чтобы вы могли сразу увидеть, где они различаются. Не уверен, насколько надежен порядок полей
Gson
, это может быть потенциальной проблемой.источник
Я перепробовал все ответы, и ничего не помогло.
Итак, я создал свой собственный метод, который сравнивает простые объекты Java, не углубляясь во вложенные структуры ...
Метод возвращает значение null, если все поля совпадают, или строка, содержащая сведения о несовпадении.
Сравниваются только свойства, у которых есть метод получения.
Как пользоваться
Пример вывода, если есть несоответствие
Вывод показывает имена свойств и соответствующие значения сравниваемых объектов.
Код (Java 8 и выше):
источник
В качестве альтернативы для junit-only вы можете установить для полей значение null до утверждения равенства:
источник
Можете ли вы поместить опубликованный вами код сравнения в какой-нибудь статический служебный метод?
Тогда вы можете использовать этот метод в JUnit следующим образом:
assertEquals («Объекты не равны», «», findDifferences (obj1, obj));
который не является громоздким и дает вам полную информацию о различиях, если они существуют (через не совсем обычную форму assertEqual, но вы получаете всю информацию, поэтому она должна быть хорошей).
источник
Это не поможет OP, но может помочь любым разработчикам C #, которые здесь окажутся ...
Как написал Энрике , вы должны переопределить метод equals.
Мое предложение - не использовать подкласс. Используйте частичный класс.
Определения частичных классов (MSDN)
Итак, ваш класс будет выглядеть ...
Что касается Java, я бы согласился с предложением использовать отражение. Просто помните, что вам следует по возможности избегать использования отражения. Это медленно, сложно отлаживать и еще сложнее поддерживать в будущем, потому что IDE могут сломать ваш код, выполнив переименование поля или что-то в этом роде. Быть осторожен!
источник
Из ваших комментариев к другим ответам я не понимаю, чего вы хотите.
Просто для обсуждения допустим, что класс действительно переопределил метод equals.
Итак, ваш UT будет выглядеть примерно так:
И все готово. Более того, вы не можете получить «полную картину равенства», если утверждение не выполняется.
Насколько я понимаю, вы говорите, что даже если бы тип переопределил equals, вас это не заинтересовало бы, поскольку вы хотите получить «полную картину равенства». Так что нет смысла расширять и отменять равные.
Итак, у вас есть варианты: либо сравнивать свойство по свойству, используя отражение или жестко запрограммированные проверки, я бы предложил последнее. Или: сравните удобочитаемые представления этих объектов.
Например, вы можете создать вспомогательный класс, который сериализует тип, который вы хотите сравнить, с XML-документом, а затем сравнивать полученный XML! в этом случае вы можете наглядно увидеть, что именно равно, а что нет.
Такой подход даст вам возможность увидеть полную картину, но он также относительно громоздок (и поначалу немного подвержен ошибкам).
источник
Вы можете переопределить метод equals класса, например:
Что ж, если вы хотите сравнить два объекта из класса, вы должны каким-то образом реализовать метод equals и метод хэш-кода
источник