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 assertThat
tanda 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 assertThat
tanda 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
assertThat
metodeMatcher<? extends T>
? Apakah ada kasus lain yang akan rusak jika Anda melakukannya? - Apakah ada gunanya generalisasi
assertThat
metode di JUnit? TheMatcher
kelas 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, karenaMatcher
hanya 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());
}
}