Почему hamcrest говорит, что байт 0 не равен int 0?
Рассмотрим следующий тестовый пример с использованием стандартных JUnit
утверждений и hamcrest 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
}
Почему это так? Значения, по-видимому, равны для JVM, потому что b == i
- true
, поэтому почему hamcrest
терпит неудачу?
Ответы
Ответ 1
Assert#assertThat
- общий метод. Примитивные типы не работают с дженериками. В этом случае byte
и int
помещаются в поле byte
и Integer
соответственно.
Затем он становится (в пределах assertThat
)
Byte b = 0;
Integer i = 0;
b.equals(i);
Byte#equals(Object)
проверяет, имеет ли аргумент тип byte
, возвращая false
немедленно, если это не так.
С другой стороны, assertEquals
Assert#assertEquals(long, long)
, и в этом случае значениям аргументов byte
и int
присвоены значения long
. Внутри это использует ==
для двух примитивных значений long
, которые равны.
Обратите внимание, что это преобразование бокса работает, потому что assertThat
объявляется как
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
где byte
помещается в ячейку byte
для T
, а int
помещается в ячейку Integer
(в пределах вызова equalTo
), но выводится как Number
для соответствия Matcher<? super T>
.
Это работает с улучшенным общим выводом Java 8. Вам нужны явные аргументы типа, чтобы он работал на Java 7.
Ответ 2
Это происходит из-за того, что int
и byte
помещаются в поле Integer
и byte
, так как hamcrest matchers работают с объектами, а не с примитивами. Таким образом, вы сравниваете Integer
с byte
, а реализация Byte.equals()
:
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
и Integer.equals()
:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Другими словами, Integer
и byte
всегда не равны. При сравнении примитивов просто используйте Assert.assertEquals
. Соединители hamcrest являются мощными, но в основном предназначены для (сложных) утверждений объектов.