Anhand des folgenden Beispiels (Verwenden von JUnit mit Hamcrest-Matchern):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
Dies wird nicht mit der assertThat
Signatur der JUnit- Methode kompiliert :
public static <T> void assertThat(T actual, Matcher<T> matcher)
Die Compiler-Fehlermeldung lautet:
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>>>)
Wenn ich jedoch die assertThat
Methodensignatur in Folgendes ändere :
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Dann funktioniert die Zusammenstellung.
Also drei Fragen:
- Warum genau wird die aktuelle Version nicht kompiliert? Obwohl ich die Kovarianzprobleme hier vage verstehe, könnte ich es sicherlich nicht erklären, wenn ich müsste.
- Gibt es einen Nachteil bei der Änderung der
assertThat
Methode aufMatcher<? extends T>
? Gibt es andere Fälle, die brechen würden, wenn Sie das tun würden? - Hat die Generierung der
assertThat
Methode in JUnit irgendeinen Sinn ? DieMatcher
Klasse scheint dies nicht zu erfordern, da JUnit die Matches-Methode aufruft, die nicht mit einem Generikum typisiert ist und nur wie ein Versuch aussieht, eine Typensicherheit zu erzwingen, die nichts tut, wie dieMatcher
einfach nicht Übereinstimmung, und der Test wird trotzdem fehlschlagen. Keine unsicheren Operationen (oder so scheint es).
Als Referenz ist hier die JUnit-Implementierung von 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());
}
}