Considérez le cas de test suivant en utilisant les assertions standard de JUnit
et l’assertion de assertThat
:
byte b = 0; int i = 0; assertEquals(b, i); // success assertThat(b, equalTo(i)); // java.lang.AssertionError: Expected: but: was if (b == i) { fail(); // test fails, so b == i is true for the JVM }
Pourquoi est-ce si? Les valeurs sont apparemment égales pour la machine virtuelle parce que b == i
est true
, alors pourquoi hamcrest
échoue-t-il?
Assert#assertThat
est une méthode générique. Les types primitifs ne fonctionnent pas avec les génériques. Dans ce cas, l’ byte
et l’ int
sont respectivement encadrés par Byte
et Integer
.
Il devient alors (dans assertThat
)
Byte b = 0; Integer i = 0; b.equals(i);
Byte#equals(Object)
implémentation Byte#equals(Object)
vérifie si l’argument est de type Byte
, renvoyant false
immédiatement si ce n’est pas le cas.
Par ailleurs, assertEquals
est assertEquals
Assert#assertEquals(long, long)
auquel cas les arguments byte
et int
sont promus en valeurs long
. En interne, cela utilise ==
sur deux valeurs long
primitives égales.
Notez que cette conversion de boxe fonctionne car assertThat
est déclaré en tant que
public static void assertThat(T actual, Matcher super T> matcher) {
où l’ byte
est encadré dans un Byte
pour T
, et le Integer
est un encadré dans un Integer
(dans l’appel de equalTo
), mais inféré sous la forme d’un Number
correspondant au Matcher super T>
Matcher super T>
.
Cela fonctionne avec l’inférence générique améliorée de Java 8. Vous aurez besoin d’arguments de type explicites pour que cela fonctionne avec Java 7.
Cela se produit parce que l’ int
et l’ byte
sont encadrés par Integer
et Byte
car les corrélateurs hamcrest opèrent sur des objects, pas sur des primitives. Donc, vous comparez un Integer
avec un Byte
, et l’implémentation de Byte.equals()
est:
public boolean equals(Object obj) { if (obj instanceof Byte) { return value == ((Byte)obj).byteValue(); } return false; }
et Integer.equals()
:
public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
En d’autres termes, un Integer
et un Byte
sont toujours inégaux. Lorsque vous comparez des primitives, utilisez simplement Assert.assertEquals
place. Les matchers hamcrest sont puissants, mais surtout destinés à des assertions d’object (complexes).