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?


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().


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.


"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.


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);
    }
}

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/


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.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.