Почему не NullValue () не компилируется при использовании с каждым элементом в Hamcrest - PullRequest
0 голосов
/ 20 июня 2019

In Hamcrest сопоставитель notNullValue() может использоваться для проверки того, что значение не равно нулю:

String string = "Foo";
assertThat(string, notNullValue());

Однако этот шаблон нельзя использовать для коллекций:

List<String> strings = Arrays.asList("Foo", "Bar");
assertThat(strings, everyItem(notNullValue()));

Поскольку это приводит к ошибке компиляции "Метод assertThat (T, Matcher) в типе MatcherAssert не применим для аргументов (List, Matcher>)".

Чем объясняется это расхождение? Как я могу сделать код компиляции?

1 Ответ

0 голосов
/ 20 июня 2019

Основная причина связана с правилами набора для универсальных классов.

Подпись 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) и другим решением (введите подстановочные знаки).

...