Как правильно сравнивать строки в Java
Что проверяют
Знаете ли вы разницу между == и equals() и умеете ли применить её в автотестах, где ожидаемый текст сравнивают с текстом со страницы или из ответа API. Следом часто спрашивают, почему тест падает, хотя на экране строки выглядят одинаково.
Как отвечать
Базовые способы:
equals(): сравнивает содержимое с учётом регистра. Безопасно кnullпишутObjects.equals(expected, actual)или вызывают метод у ожидаемой строки:"Оплачено".equals(actual);==: сравнивает ссылки, а не текст. Одинаковые литералы лежат в пуле строк, поэтому на них==случайно даётtrue, а строка изgetText(), JSON или файла это новый объект;equalsIgnoreCase(): без учёта регистра, когда регистр не входит в требование;compareTo(): лексикографический порядок, нужен для проверки сортировки в таблице. Для сортировки «как у людей» с учётом языка естьCollator.
В тестах строки сравнивают ассертами, а не через if:
- JUnit 5:
assertEquals(expected, actual), порядок аргументов важен, от него зависит понятность отчёта; - AssertJ:
assertThat(actual).isEqualTo(expected), а такжеisEqualToIgnoringCase,isEqualToIgnoringWhitespace,isEqualToNormalizingWhitespace,contains,startsWith.
Отдельно скажите про данные из UI: текст приходит с переносами, двойными пробелами и неразрывным пробелом \u00A0. Его не убирают ни trim(), ни strip(), поэтому перед сравнением его заменяют явно: text.replace('\u00A0', ' ').
Где спотыкаются
Пишут assertTrue(actual == expected). Локально на литералах тест зелёный, на реальных данных падает, а сообщение об ошибке ничего не объясняет.
Путают местами expected и actual. Тест падает правильно, но в отчёте ожидаемым значением оказывается то, что пришло со страницы, и разбор бага идёт по ложному следу.
Сравнивают сырой текст элемента с шаблоном целиком. Любой перенос строки или неразрывный пробел превращает тест во флаки. Надёжнее проверять смысловую часть или нормализовать строку перед сравнением.