org matchers equalto corematchers containsstring assertequals java junit hamcrest

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.