Pourquoi hamcrest dit-il qu’un octet 0 n’est pas égal à un int 0?

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 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 Matcher .

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).