Dans l'exemple suivant (en utilisant JUnit avec des matchers Hamcrest):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
Cela ne se compile pas avec la assertThat
signature de la méthode JUnit de:
public static <T> void assertThat(T actual, Matcher<T> matcher)
Le message d'erreur du compilateur est:
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>>>)
Cependant, si je change la assertThat
signature de la méthode en:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
Ensuite, la compilation fonctionne.
Donc trois questions:
- Pourquoi exactement la version actuelle ne compile-t-elle pas? Bien que je comprenne vaguement les problèmes de covariance ici, je ne pourrais certainement pas l'expliquer si je le devais.
- Y a-t-il un inconvénient à changer la
assertThat
méthodeMatcher<? extends T>
? Y a-t-il d'autres cas qui se briseraient si vous faisiez cela? - Y a-t-il un intérêt à la générisation de la
assertThat
méthode dans JUnit? LaMatcher
classe ne semble pas l'exiger, car JUnit appelle la méthode matches, qui n'est pas typée avec un générique, et ressemble simplement à une tentative de forcer une sécurité de type qui ne fait rien, car laMatcher
volonté n'est tout simplement pas en fait correspond et le test échouera malgré tout. Aucune opération dangereuse n'est impliquée (ou du moins il semble).
Pour référence, voici l'implémentation JUnit de 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());
}
}