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 assertThatSignatur 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 assertThatMethodensignatur 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
assertThatMethode aufMatcher<? extends T>? Gibt es andere Fälle, die brechen würden, wenn Sie das tun würden? - Hat die Generierung der
assertThatMethode in JUnit irgendeinen Sinn ? DieMatcherKlasse 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 dieMatchereinfach 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());
}
}