Подтвердить что ты не робот

Почему 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 терпит неудачу?

4b9b3361

Ответ 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 являются мощными, но в основном предназначены для (сложных) утверждений объектов.