Учитывая следующий пример (используя JUnit с совпадениями Hamcrest):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
Это не компилируется с помощью сигнатуры метода JUnit assertThat
:
public static <T> void assertThat(T actual, Matcher<T> matcher)
Сообщение об ошибке компилятора:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
Однако, если я изменяю сигнатуру метода assertThat
на:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Затем компиляция работает.
Итак, три вопроса:
- Почему точно не компилируется текущая версия? Хотя я смутно понимаю проблемы ковариации здесь, я, конечно, не мог объяснить это, если бы мне пришлось.
- Есть ли недостаток в изменении метода
assertThat
наMatcher<? extends T>
? Существуют ли другие случаи, которые могут сломаться, если вы это сделали? - Есть ли какая-либо точка для обобщения метода
assertThat
в JUnit? КлассMatcher
, похоже, не требует этого, поскольку JUnit вызывает метод совпадений, который не набирается с каким-либо общим, и просто выглядит как попытка принудительного сохранения типа, который ничего не делает, посколькуMatcher
будет просто не совпадать, и тест будет терпеть неудачу. Никаких небезопасных операций (или, как кажется).
Для справки, вот реализация JUnit assertThat
:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}