Основная причина связана с правилами набора для универсальных классов.
Подпись assertThat
равна assertThat(T actual, Matcher<? super T> matcher)
, что означает, что параметр типа matcher
, передаваемый в качестве аргумента, должен быть таким же, или супертип , типа actual
значение.
Тип, возвращаемый notNullValue()
, равен Matcher<Object>
. Таким образом, типы соответствуют:
String string = "Foo";
assertThat(string, notNullValue());
Потому что Object
является супертипом String
.
С everyItem
все по-другому. Подпись everyItem
:
Matcher<Iterable<U>> everyItem(Matcher<U> itemMatcher)
Это означает, что тип возвращаемого значения everyItem(notNullValue())
равен Matcher<Iterable<Object>>
.
Если мы посмотрим на предполагаемые типы в вызове assertThat
, это означает:
assertThat(List<String>, Matcher<Iterable<Object>>)
Однако, хотя List<T>
является подтипом Iterable<T>
и String
является подтипом Object
, это не тот случай, когда List<String>
является подтипом Iterable<Object>
по соображениям безопасности типа. Таким образом, ограничения типа в сигнатуре assertThat
не соблюдаются.
К счастью, Hamcrest предоставляет универсальную версию из notNullValue
, которая использует аргумент класса для обеспечения более точного типа возвращаемого значения.
Таким образом, решение заключается в использовании:
assertThat(strings, everyItem(notNullValue(String.class)));
Если мы разберем это, мы получим:
List<String> strings = Arrays.asList("Foo", "Bar");
Matcher<String> notNullMatcher = notNullValue(String.class);
Matcher<Iterable<String>> everyItemMatcher = everyItem(notNullMatcher);
assertThat(strings, everyItemMatcher);
Поскольку List<String>
является подтипом Iterable<String>
, все работает.
См. этот пост для версии этой проблемы с другим средством сопоставления (getKey
) и другим решением (введите подстановочные знаки).