Diberikan contoh berikut (menggunakan JUnit dengan pencocokan Hamcrest):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
Ini tidak dikompilasi dengan assertThattanda tangan metode JUnit dari:
public static <T> void assertThat(T actual, Matcher<T> matcher)
Pesan kesalahan kompiler adalah:
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>>>)
Namun, jika saya mengubah assertThattanda tangan metode ke:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Kemudian kompilasi bekerja.
Jadi tiga pertanyaan:
- Mengapa sebenarnya tidak mengkompilasi versi saat ini? Meskipun saya samar-samar memahami masalah kovarian di sini, saya jelas tidak bisa menjelaskannya jika saya harus.
- Apakah ada kerugian dalam mengubah
assertThatmetodeMatcher<? extends T>? Apakah ada kasus lain yang akan rusak jika Anda melakukannya? - Apakah ada gunanya generalisasi
assertThatmetode di JUnit? TheMatcherkelas tampaknya tidak memerlukannya, karena JUnit memanggil metode pertandingan, yang tidak diketik dengan penampilan generik, dan hanya seperti sebuah upaya untuk memaksa keselamatan jenis yang tidak melakukan apa-apa, karenaMatcherhanya akan tidak sebenarnya cocok, dan tes akan gagal terlepas. Tidak ada operasi yang tidak aman yang terlibat (atau begitulah tampaknya).
Untuk referensi, berikut ini adalah implementasi JUnit dari 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());
}
}