funciona - Java: ¿Es confiable assertEquals(String, String)?
junit (7)
Sé que ==
tiene algunos problemas al comparar dos Strings
. Parece que String.equals()
es un mejor enfoque. Bueno, estoy haciendo pruebas JUnit y mi inclinación es usar assertEquals(str1, str2)
. ¿Es esta una manera confiable de afirmar que dos cadenas contienen el mismo contenido? assertTrue(str1.equals(str2))
, pero luego no obtendrá el beneficio de ver cuáles son los valores esperados y reales en caso de falla.
En una nota relacionada, ¿alguien tiene un enlace a una página o hilo que explica claramente los problemas con str1 == str2
?
"El operador
==
verifica si dosObjects
son exactamente el mismoObject
".
http://leepoint.net/notes-java/data/strings/12stringcomparison.html
String
es un Object
en Java, por lo que entra en esa categoría de reglas de comparación.
El JUnit assertEquals(obj1, obj2)
llama a obj1.equals(obj2)
.
También hay assertSame(obj1, obj2)
que obj1 == obj2
(es decir, verifica que obj1
y obj2
hacen referencia a la misma instancia), que es lo que intentas evitar.
Entonces estás bien.
En pocas palabras, puede tener dos objetos String que contengan los mismos caracteres pero que sean objetos diferentes (en diferentes ubicaciones de memoria). El operador == comprueba que dos referencias apuntan al mismo objeto (ubicación de la memoria), pero el método equals () comprueba si los caracteres son iguales.
Por lo general, le interesa comprobar si dos cadenas contienen los mismos caracteres, no si apuntan a la misma ubicación de memoria.
Sí, se usa todo el tiempo para las pruebas. Es muy probable que el marco de prueba use .equals () para comparaciones como estas.
A continuación hay un enlace que explica el "error de igualdad de cadenas". Básicamente, las cadenas en Java son objetos, y cuando se compara la igualdad de objetos, generalmente se comparan en función de la dirección de la memoria y no del contenido. Debido a esto, dos cadenas no ocuparán la misma dirección, incluso si su contenido es idéntico, por lo que no coincidirán correctamente, aunque tengan el mismo aspecto cuando se impriman.
http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/
Siempre debe usar .equals()
al comparar Strings
en Java.
JUnit llama al método .equals()
para determinar la igualdad en el método assertEquals(Object o1, Object o2)
.
Entonces, definitivamente estás seguro usando assertEquals(string1, string2)
. (Porque las String
son Object
s)
Aquí hay un enlace a una gran pregunta de con respecto a algunas de las diferencias entre ==
y .equals()
.
assertEquals
usa el método de equals
para la comparación. Hay una assertSame
diferente, assertSame
, que usa el operador ==
.
Para entender por qué ==
no se debe usar con cadenas, debe comprender qué ==
hace: realiza una verificación de identidad. Es decir, a == b
comprueba si a
y b
refieren al mismo objeto . Está integrado en el lenguaje y su comportamiento no puede ser modificado por diferentes clases. El método equals
, por otro lado, puede ser anulado por clases. Si bien su comportamiento predeterminado (en la clase Object
) es realizar una comprobación de identidad con el operador ==
, muchas clases, incluido String
, lo reemplazan para realizar una comprobación de "equivalencia" en su lugar. En el caso de String
, en lugar de verificar si a
y b
refieren al mismo objeto, a.equals(b)
comprueba si los objetos a los que se refieren son cadenas que contienen exactamente los mismos caracteres.
Tiempo de analogía: imagine que cada objeto String
es un trozo de papel con algo escrito en él. Digamos que tengo dos pedazos de papel con "Foo" escrito en ellos, y otro con "Barra" escrito en él. Si tomo los primeros dos trozos de papel y uso ==
para compararlos, se devolverá false
porque esencialmente se está preguntando "¿son estos el mismo trozo de papel?". No necesita ni siquiera mirar lo que está escrito en el papel. El hecho de que le doy dos hojas de papel (en lugar de la misma dos veces) significa que devolverá false
. Sin embargo, si uso equals
, el método de equals
leerá los dos trozos de papel y verá que dicen lo mismo ("Foo"), por lo que volverá a ser true
.
El bit que se confunde con Strings es que Java tiene un concepto de "interning" Strings, y esto se realiza (efectivamente) automáticamente en cualquier literal de cadena en su código. Esto significa que si tiene dos literales equivalentes en su código (incluso si están en diferentes clases), ambos se referirán al mismo objeto String
. Esto hace que el operador ==
devuelva true
más a menudo de lo que cabría esperar.
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);
}
}