La méthode assertEquals de Java est-elle fiable?

199

Je sais que cela ==pose quelques problèmes lors de la comparaison de deux Strings. Il paraît queString.equals() soit une meilleure approche. Eh bien, je fais des tests JUnit et mon inclination est d'utiliser assertEquals(str1, str2). Est-ce un moyen fiable d'affirmer que deux chaînes contiennent le même contenu? J'utiliserais assertTrue(str1.equals(str2)), mais vous n'obtenez pas l'avantage de voir quelles sont les valeurs attendues et réelles en cas d'échec.

Sur une note connexe, quelqu'un a-t-il un lien vers une page ou un fil qui explique clairement les problèmes str1 == str2?

DivideByHero
la source
1
Si vous n'êtes pas sûr, vous pouvez lire le code ou le Javadoc. BTW si vous voulez tester ce sont les mêmes objets que vous pouvez utiliser assertSame.
Peter Lawrey
2
Si str1 et str2 sont null, assertEquals () est vrai, mais assertTrue (str1.equals (str2)) lève une exception. Le premier exemple imprimera également un message d'erreur utile tel que le contenu de str1 et str2, le second ne le fait pas.
Peter Lawrey

Réponses:

274

Vous devez toujours utiliser .equals()lors de la comparaison Stringsen Java.

JUnit appelle la .equals()méthode pour déterminer l'égalité dans la méthodeassertEquals(Object o1, Object o2) .

Donc, vous êtes certainement en sécurité assertEquals(string1, string2). (Parce que Strings sont Objects)

Voici un lien vers une grande question Stackoverflow concernant certaines des différences entre ==et .equals().

jjnguy
la source
12
IIRC assertEquals () réussit si les deux chaînes sont nulles. Si ce n'est pas ce que vous voulez, appelez également assertNotNull ().
fin
10
de plus, si vous voulez tester pour ==, vous pouvez appeler assertSame ()
james
7
Je ne dirais pas toujours ; parfois, l'égalité de référence est souhaitée, même pour les chaînes.
Karu
30

assertEqualsutilise la equalsméthode pour la comparaison. Il existe une assertion différente assertSame, qui utilise l' ==opérateur.

Pour comprendre pourquoi ==ne devrait pas être utilisé avec des chaînes, vous devez comprendre ce qui ==fait: il fait un contrôle d'identité. Autrement dit, a == bvérifie si aet fait bréférence au même objet . Il est intégré au langage et son comportement ne peut pas être modifié par différentes classes. La equalsméthode, en revanche, peut être remplacée par des classes. Bien que son comportement par défaut (dans la Objectclasse) consiste à effectuer un contrôle d'identité à l'aide de l' ==opérateur, de nombreuses classes, y compris String, le remplacent pour effectuer à la place un contrôle "d'équivalence". Dans le cas de String, au lieu de vérifier si vérifie pour voir si les objets auxquels ils se réfèrent sont les deux chaînes qui contiennent exactement les mêmes caractères.a etb faire référence au même objet,a.equals(b)

Temps d'analogie: imaginez que chaque Stringobjet est un morceau de papier avec quelque chose d'écrit dessus. Disons que j'ai deux morceaux de papier avec "Foo" écrits dessus, et un autre avec "Bar" écrit dessus. Si je prends les deux premiers morceaux de papier et que je les utilise ==pour les comparer, cela reviendra falsecar il s'agit essentiellement de demander "S'agit-il du même morceau de papier?". Il n'a même pas besoin de regarder ce qui est écrit sur le papier. Le fait que je lui donne deux morceaux de papier (plutôt que le même deux fois) signifie qu'il reviendra false. Si j'utilise equals, cependant, la equalsméthode lira les deux morceaux de papier et verra qu'ils disent la même chose ("Foo"), et donc ça reviendra true.

Le bit qui devient confus avec Strings est que Java a un concept de "interning" Strings, et cela est (effectivement) automatiquement effectué sur tous les littéraux de chaîne dans votre code. Cela signifie que si vous avez deux littéraux de chaîne équivalents dans votre code (même s'ils sont dans des classes différentes), ils se réfèrent tous deux au même Stringobjet. Cela fait que l' ==opérateur revient trueplus souvent que ce à quoi on pourrait s'attendre.

Laurence Gonsalves
la source
"Autrement dit, a == b vérifie si a et b sont le même objet." Techniquement, il vérifie si a et b font référence au même objet, car a et b sont des références. A moins que je ne me trompe.
bob
@ user1903064 qui est correct. Étant donné que les variables non primitives ne peuvent contenir que des références en Java, il est courant d'ignorer le niveau supplémentaire d'indirection lorsque vous en parlez, mais je conviens que dans ce cas, être plus explicite est bénéfique. J'ai mis à jour la réponse. Merci pour la suggestion!
Laurence Gonsalves
7

En bref - vous pouvez avoir deux objets String qui contiennent les mêmes caractères mais sont des objets différents (dans des emplacements de mémoire différents). L'opérateur == vérifie que deux références pointent vers le même objet (emplacement mémoire), mais la méthode equals () vérifie si les caractères sont les mêmes.

Habituellement, vous souhaitez vérifier si deux chaînes contiennent les mêmes caractères, et non si elles pointent vers le même emplacement mémoire.

Ken Liu
la source
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
la source
3

Oui, il est utilisé tout le temps pour les tests. Il est très probable que le cadre de test utilise .equals () pour des comparaisons comme celles-ci.

Ci-dessous un lien expliquant "l'erreur d'égalité de chaîne". Essentiellement, les chaînes en Java sont des objets et lorsque vous comparez l'égalité des objets, elles sont généralement comparées en fonction de l'adresse mémoire et non en fonction du contenu. Pour cette raison, deux chaînes n'occuperont pas la même adresse, même si leur contenu est identique, elles ne correspondront donc pas correctement, même si elles se ressemblent lors de l'impression.

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

Soviut
la source
3

La JUnit assertEquals(obj1, obj2)appelle en effet obj1.equals(obj2).

Il y a aussi assertSame(obj1, obj2)ce qui le fait obj1 == obj2(c'est-à-dire qu'il vérifie cela obj1et obj2fait référence à la même instance), ce que vous essayez d'éviter.

Alors tu vas bien.

Jack Leow
la source
0

"L' ==opérateur vérifie si deux Objectssont exactement identiques Object."

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

Stringest un Objecten java, donc il tombe dans cette catégorie de règles de comparaison.

Zachery Delafosse
la source
Cela n'a pas répondu à la question et est un peu trompeur. Vous ne pouvez pas faire == sur une chaîne de manière fiable
CodeMonkey