java - matchers - ¿Por qué hamcrest dice que un byte 0 no es igual a un int 0?
import static org hamcrest corematchers containsstring (2)
Considere el siguiente caso de prueba utilizando aserciones de JUnit
estándar y aseveración de assertThat
:
byte b = 0;
int i = 0;
assertEquals(b, i); // success
assertThat(b, equalTo(i)); // java.lang.AssertionError: Expected: <0> but: was <0>
if (b == i) {
fail(); // test fails, so b == i is true for the JVM
}
¿Por qué es así? Los valores son aparentemente iguales para JVM porque b == i
es true
, entonces ¿por qué falla hamcrest
?
Esto sucede porque el int
y el byte
están encajonados en Integer
y Byte
ya que los comparadores de hamcrest operan en objetos, no en primitivos. Entonces, estás comparando un Integer
con un Byte
, y la implementación de Byte.equals()
es:
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
y Integer.equals()
:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
En otras palabras, un Integer
y un Byte
son siempre desiguales. Cuando se comparan primitivas, solo use Assert.assertEquals
en Assert.assertEquals
lugar. Los comparadores de hamcrest son poderosos, pero en su mayoría están destinados a aserciones de objetos (complejos).
Assert#assertThat
es un método genérico. Los tipos primitivos no funcionan con los genéricos. En este caso, el byte
y el int
se encajonan en el Byte
y el Integer
, respectivamente.
Entonces se convierte (dentro de assertThat
)
Byte b = 0;
Integer i = 0;
b.equals(i);
Byte#equals(Object)
la implementación de Byte#equals(Object)
verifica si el argumento es de tipo Byte
, devolviendo false
inmediatamente si no lo es.
Por otro lado, assertEquals
es Assert#assertEquals(long, long)
en cuyo caso los argumentos byte
e int
se promueven a valores long
. Internamente, esto usa ==
en dos valores long
primitivos que son iguales.
Tenga en cuenta que esta conversión de boxeo funciona porque assertThat
se declara como
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
donde el byte
está encuadrado en un Byte
para T
, y el int
es un recuadro en un Integer
(dentro de la llamada a equalTo
), pero se infiere como un Number
para coincidir con el Matcher<? super T>
Matcher<? super T>
.
Esto funciona con la inferencia genérica mejorada de Java 8. Necesitaría argumentos de tipo explícito para que funcione en Java 7.