Ist die assertEquals-Methode von Java zuverlässig?

199

Ich weiß, dass ==es beim Vergleich von zwei Probleme gibt Strings. Es scheint, dass dies String.equals()ein besserer Ansatz ist. Nun, ich mache JUnit-Tests und meine Neigung ist es, sie zu verwenden assertEquals(str1, str2). Ist dies eine zuverlässige Methode, um zu behaupten, dass zwei Strings denselben Inhalt enthalten? Ich würde verwenden assertTrue(str1.equals(str2)), aber dann haben Sie nicht den Vorteil zu sehen, was die erwarteten und tatsächlichen Werte bei einem Fehler sind.

Hat jemand einen Link zu einer Seite oder einem Thread, der die Probleme mit klar erklärt str1 == str2?

DivideByHero
quelle
1
Wenn Sie sich nicht sicher sind, können Sie den Code oder den Javadoc lesen. Übrigens, wenn Sie testen möchten, dass es sich um dasselbe Objekt handelt, können Sie assertSame verwenden.
Peter Lawrey
2
Wenn str1 und str2 null sind, ist assertEquals () wahr, aber assertTrue (str1.equals (str2)) löst eine Ausnahme aus. Das erste Beispiel gibt auch eine nützliche Fehlermeldung aus, z. B. den Inhalt von str1 und str2, das zweite nicht.
Peter Lawrey

Antworten:

274

Sie sollten immer verwenden .equals()beim Vergleich Stringsin Java.

JUnit ruft die .equals()Methode auf, um die Gleichheit in der Methode zu bestimmen assertEquals(Object o1, Object o2).

Sie sind also auf jeden Fall sicher assertEquals(string1, string2). (Weil Strings s sind Object)

Hier ist ein Link zu einer großartigen Stackoverflow-Frage zu einigen Unterschieden zwischen ==und .equals().

jjnguy
quelle
12
IIRC assertEquals () ist erfolgreich, wenn beide Zeichenfolgen null sind. Wenn dies nicht das ist, was Sie wollen, rufen Sie auch assertNotNull () auf.
Finnw
10
Wenn Sie auf == testen möchten, können Sie außerdem assertSame ()
james aufrufen
7
Ich würde nicht immer sagen ; Manchmal ist eine Referenzgleichheit erwünscht, selbst für Zeichenfolgen.
Karu
30

assertEqualsverwendet die equalsMethode zum Vergleich. Es gibt eine andere Behauptung assertSame, die den ==Operator verwendet.

Um zu verstehen, warum ==nicht mit Zeichenfolgen verwendet werden sollte, müssen Sie verstehen, was ==funktioniert: Es wird eine Identitätsprüfung durchgeführt. Das heißt, es wird a == bgeprüft, ob aund bauf dasselbe Objekt verwiesen wird . Es ist in die Sprache integriert und kann von verschiedenen Klassen nicht geändert werden. Die equalsMethode kann dagegen von Klassen überschrieben werden. Während das Standardverhalten (in der ObjectKlasse) darin besteht, eine Identitätsprüfung mit dem ==Operator durchzuführen String, überschreiben viele Klassen, einschließlich , diese, um stattdessen eine "Äquivalenz" -Prüfung durchzuführen. Im Fall von String, anstatt zu prüfen, ob aund bauf dasselbe Objekt verweisen,a.equals(b) Überprüft, ob es sich bei den Objekten, auf die sie verweisen, um Zeichenfolgen handelt, die genau dieselben Zeichen enthalten.

Analogiezeit: Stellen Sie sich vor, jedes StringObjekt ist ein Stück Papier, auf dem etwas geschrieben ist. Nehmen wir an, ich habe zwei Zettel mit "Foo" und ein weiteres mit "Bar". Wenn ich die ersten beiden Zettel nehme und ==zum Vergleichen verwende, wird sie zurückgegebenfalse da im Wesentlichen gefragt dasselbe Zettel handelt. Es muss nicht einmal darauf achten, was auf dem Papier steht. Die Tatsache, dass ich ihm zwei Blatt Papier gebe (anstatt zweimal dasselbe), bedeutet, dass es zurückkehren wird false. Wenn ich equalsjedoch verwende, equalsliest die Methode die beiden Zettel und stellt fest, dass sie dasselbe sagen ("Foo"), und kehrt daher zurück true.

Das mit Strings verwirrende Bit ist, dass Java ein Konzept zum "Internieren" von Strings hat, das (effektiv) automatisch für alle String-Literale in Ihrem Code ausgeführt wird. Dies bedeutet, dass wenn Sie zwei äquivalente Zeichenfolgenliterale in Ihrem Code haben (auch wenn sie sich in verschiedenen Klassen befinden), beide tatsächlich auf dasselbe StringObjekt verweisen . Dadurch ==kehrt der Bediener truehäufiger zurück als erwartet.

Laurence Gonsalves
quelle
"Das heißt, a == b prüft, ob a und b dasselbe Objekt sind." Technisch wird geprüft, ob sich a und b auf dasselbe Objekt beziehen, da a und b Referenzen sind. Es sei denn, ich liege sehr falsch.
Bob
@ user1903064 das ist richtig. Da nicht-primitive Variablen nur Verweise in Java enthalten können, ist es üblich, die zusätzliche Indirektionsebene zu überspringen, wenn über sie gesprochen wird. Ich stimme jedoch zu, dass es in diesem Fall von Vorteil ist, expliziter zu sein. Ich habe die Antwort aktualisiert. Danke für den Vorschlag!
Laurence Gonsalves
7

Kurz gesagt: Sie können zwei String-Objekte haben, die dieselben Zeichen enthalten, aber unterschiedliche Objekte sind (an unterschiedlichen Speicherorten). Der Operator == überprüft, ob zwei Referenzen auf dasselbe Objekt (Speicherort) verweisen. Die Methode equals () überprüft jedoch, ob die Zeichen identisch sind.

Normalerweise möchten Sie überprüfen, ob zwei Zeichenfolgen dieselben Zeichen enthalten und nicht, ob sie auf denselben Speicherort verweisen.

Ken Liu
quelle
4
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);
    }
}
Carl Manaster
quelle
3

Ja, es wird ständig zum Testen verwendet. Es ist sehr wahrscheinlich, dass das Testframework .equals () für solche Vergleiche verwendet.

Unten finden Sie einen Link, der den "String Equality Error" erklärt. Im Wesentlichen sind Zeichenfolgen in Java Objekte. Wenn Sie die Objektgleichheit vergleichen, werden sie normalerweise anhand der Speicheradresse und nicht anhand des Inhalts verglichen. Aus diesem Grund belegen zwei Zeichenfolgen nicht dieselbe Adresse, auch wenn ihr Inhalt identisch ist, sodass sie nicht richtig übereinstimmen, obwohl sie beim Drucken gleich aussehen.

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

Soviut
quelle
3

Die JUnit assertEquals(obj1, obj2)ruft tatsächlich an obj1.equals(obj2).

Es gibt auch assertSame(obj1, obj2) welche obj1 == obj2, die dies tun (dh dies überprüfen obj1und obj2auf dasselbe verweisen) , die dies tun Instanz ), was Sie vermeiden möchten.

Also geht es dir gut.

Jack Leow
quelle
0

"Der ==Bediener prüft, ob zwei Objectsgenau gleich sind Object."

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

Stringist ein Objectin Java, so fällt es in diese Kategorie von Vergleichsregeln.

Zachery Delafosse
quelle
Dies hat die Frage nicht beantwortet und ist irreführend. Sie können == auf einer Zeichenfolge nicht zuverlässig ausführen
CodeMonkey