Является ли метод Java assertEquals надежным? - PullRequest
190 голосов
/ 29 июля 2009

Я знаю, что == имеет некоторые проблемы при сравнении двух Strings. Кажется, что String.equals() - лучший подход. Ну, я провожу тестирование JUnit, и я склонен использовать assertEquals(str1, str2). Это надежный способ утверждать, что две строки содержат одинаковое содержимое? Я бы использовал assertTrue(str1.equals(str2)), но тогда вы не получите преимущества от просмотра ожидаемых и фактических значений при сбое.

В связанной заметке, есть ли у кого-нибудь ссылка на страницу или тему, которая явно объясняет проблемы с str1 == str2?

Ответы [ 7 ]

263 голосов
/ 29 июля 2009

Вы должны всегда использовать .equals() при сравнении Strings в Java.

JUnit вызывает метод .equals() для определения равенства в методе assertEquals(Object o1, Object o2).

Итак, вы определенно в безопасности, используя assertEquals(string1, string2). (Потому что String с Object с)

Вот ссылка на большой вопрос Stackoverflow относительно некоторых различий между == и .equals().

30 голосов
/ 29 июля 2009

assertEquals использует метод equals для сравнения. Существует другое утверждение, assertSame, в котором используется оператор ==.

Чтобы понять, почему == не следует использовать со строками, вам необходимо понять, что делает ==: он выполняет проверку личности. То есть a == b проверяет, относятся ли a и b к одному и тому же объекту . Он встроен в язык, и его поведение не может быть изменено различными классами. Метод equals, с другой стороны, может быть переопределен классами. Хотя его поведение по умолчанию (в классе Object) заключается в проверке идентичности с использованием оператора ==, многие классы, включая String, переопределяют его, вместо этого выполняя проверку "эквивалентности". В случае String вместо проверки того, ссылаются ли a и b на один и тот же объект, a.equals(b) проверяет, являются ли объекты, на которые они ссылаются, строками, которые содержат абсолютно одинаковые символы.

Время аналогии: представьте, что каждый String объект - это лист бумаги с чем-то написанным на нем. Допустим, у меня есть два листа бумаги с надписью «Foo» и еще один с надписью «Bar». Если я возьму первые два листа бумаги и использую ==, чтобы сравнить их, он вернет false, потому что он по сути спрашивает: «Это один и тот же лист бумаги?». Не нужно даже смотреть на то, что написано на бумаге. Тот факт, что я даю ему два листа бумаги (а не один и тот же дважды), означает, что он вернет false. Однако, если я использую equals, метод equals прочитает два листа бумаги и увидит, что они говорят одно и то же («Foo»), и поэтому вернет true.

Ситуация, которая путает со строками, заключается в том, что в Java есть концепция "интернирования" строк, и это (эффективно) автоматически выполняется для любых строковых литералов в вашем коде. Это означает, что если в вашем коде есть два эквивалентных строковых литерала (даже если они находятся в разных классах), они на самом деле оба ссылаются на один и тот же объект String. Это делает оператор == возвращающим true чаще, чем можно было бы ожидать.

7 голосов
/ 29 июля 2009

В двух словах - у вас может быть два объекта String, которые содержат одинаковые символы, но являются разными объектами (в разных местах памяти). Оператор == проверяет, что две ссылки указывают на один и тот же объект (область памяти), но метод equals () проверяет, совпадают ли символы.

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

3 голосов
/ 29 июля 2009

JUnit assertEquals(obj1, obj2) действительно вызывает obj1.equals(obj2).

Также есть assertSame(obj1, obj2), который делает obj1 == obj2 (то есть проверяет, что obj1 и obj2 ссылаются на тот же экземпляр), чего вы пытаетесь избежать.

Так что ты в порядке.

3 голосов
/ 29 июля 2009
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}
3 голосов
/ 29 июля 2009

Да, он все время используется для тестирования. Весьма вероятно, что среда тестирования использует .equals () для таких сравнений.

Ниже приведена ссылка, объясняющая «ошибку равенства строк». По сути, строки в Java являются объектами, и когда вы сравниваете равенство объектов, обычно они сравниваются по адресу памяти, а не по содержимому. Из-за этого две строки не будут занимать один и тот же адрес, даже если их содержимое идентично, поэтому они не будут соответствовать друг другу, даже если при печати они выглядят одинаково.

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/

0 голосов
/ 29 июля 2009

"Оператор == проверяет, совпадают ли два Objects Object."

http://leepoint.net/notes-java/data/strings/12stringcomparison.html

String - это Object в Java, поэтому он попадает в эту категорию правил сравнения.

...