Должен ли я unit test hashCode/equals/toString?

При написании классов Java нередко генерировать методы с использованием вашей среды IDE, такие как

  • toString()
  • equals()
  • hashCode()

Но как только вы сгенерировали их с помощью IDE, они станут частью вашей базы кода (в SCM), и поэтому применяются все средства измерения качества.

В частности, методы equals и hashcode содержат множество условий. Если я не пишу модульные тесты, оценка по охвату кода (line-, condition-, mutation-) довольно низкая, особенно если тестируемый класс не такой большой.

Некоторые средства поддержки охвата поддерживают фильтрацию (то есть кобертуру), другие (т.е. jacoco) - нет. Но инструменты охвата показывают только симптом - непроверенный код - и поэтому я не спрашиваю, следует ли подавлять/игнорировать симптом, но как бороться с основной причиной.

Вопрос: должен ли я писать модульные тесты для этих методов?

  • Если да, каковы веские причины для этого? И какой разумный подход?
  • Если нет, почему бы и нет?

Я не прошу создания сгенерированных классов вообще, таких как JAXB pojos, WS-Clients и т.д., которые можно легко сгенерировать автоматически и исключить из анализа покрытия.

Ответ 1

Если вы создаете эти методы, вы должны, вероятно, также генерировать тесты для него; -)

Это может быть громоздким для проверки этих методов вручную, но в зависимости от того, что вы хотите обеспечить с помощью своих тестов, может быть целесообразно проверить эти методы. Встречный вопрос: проверяете ли вы логические записи?

Это действительно зависит от того, что вы пытаетесь выполнить. Некоторые скажут: "нет", другие могут сказать: do.

Думая о некоторых причинах, чтобы не тестировать такие методы:

  • генерируется код и может содержать много полей. тестирование может привести к множеству различных комбинаций, которые были бы просто громоздкими для написания/поддержки, и, возможно, генератор уже был проверен достаточно хорошо?; -)
  • вы не получаете никакой ценности, применяя для этого тесты. Ваш toString() будет использоваться только журналами или отладчиком, поэтому вам все равно.
  • вы доверяете, что сгенерированный код достаточно безопасен для hashcode и equals

Причины тестирования таких методов:

  • чтобы гарантировать, что результат будет таким, как ожидалось
  • вы хотите убедиться, что если вы регенерируете эти методы, они не нарушают использование предыдущей реализации программы.
  • вы используете свой toString() -метод, кроме ведения журнала, и не хотите, чтобы некоторые вещи отображались там. Как сказал Халк, вы также можете убедиться, что некоторые вещи даже не отображаются в журналах.

Но они были скорее составлены. В последних проектах я не тестировал toString() и equals или hashcode только редко, поскольку это не считалось необходимым, и все согласились.

Возможно, все сводится к: насколько вам безопасен ваш код и насколько он вам стоит (или ваш бизнес или ваш клиент; -))

Ответ 2

Проблема с IDE, сгенерированным hashCode/equals, заключается в том, что он может не синхронизироваться с самим объектом (например, при добавлении новых полей). Поэтому я бы посоветовал создавать тесты для hashCode и equals.

Конечно, было бы неоптимально писать их вручную. Вы можете использовать автоматизированные инструменты, такие как проект EqualsVerifier, чтобы сделать их однострочными.

toString - другой зверь, так как у него нет определенного контракта. Если вы используете toString просто для того, чтобы получить более приятный опыт отладки, я бы не стал его тестировать и просто удалил бы его из расчетов покрытия.

Ответ 3

Да, я бы проверил все это. Недостаточно сказать, что тесты не нужны, так как они генерируются автоматически. Кто-то может легко добавить новое поле и забыть восстановить код равенства/хэш-код и строку.

Тестирование на строку, пожалуй, является самым спорным из всего этого, но я думаю, что оно необходимо, особенно если вы входите в свое приложение.

Как уже было предложено другими, EqualsVerifier, вероятно, является лучшим подходом для тестирования equals и хэш-кода.

Что касается тестирования метода toString, попробуйте ToStringVerifier. Тест так же прост, как:

@Test
public void testToString() {
    ToStringVerifier.forClass(User.class)
                  .withClassName(NameStyle.SIMPLE_NAME)
                  .verify();
}

Ответ 4

Эти методы бесполезны сами по себе. Если вы не используете эти классы в коллекциях (например, HashSet/HashMap), или если вы никогда не проверяете эти экземпляры классов на равенство - вам не нужны модульные тесты. И в этом случае я бы просто отключил плагин, который их генерирует, как предлагал @ByeBye.

Но если вы действительно делаете что-либо из этого, вам нужны модульные тесты. Если некорректная реализация может привести к ошибке вашего приложения или неправильному поведению - эта реализация должна охватываться модульными тестами.

Ответ 5

То же самое для внешних библиотек - вы не должны тестировать методы equals и hashcode при его создании. Плагин, который проверяет покрытие, должен иметь некоторый механизм, чтобы игнорировать эти сгенерированные источники.

Нет никаких веских оснований для тестирования сгенерированного кода, никакой разницы, если это сгенерированный метод в вашем классе или целый класс.

Если вы в зависимости от внешнего механизма, вы должны полагать, что он создан правильно.