次の例があるとします(JUnitとHamcrestマッチャーを使用)。
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
これは、以下のJUnit assertThat
メソッドシグネチャでコンパイルされません。
public static <T> void assertThat(T actual, Matcher<T> matcher)
コンパイラのエラーメッセージは次のとおりです。
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>>>)
ただし、assertThat
メソッドシグネチャを次のように変更した場合:
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
その後、コンパイルが機能します。
したがって、3つの質問:
- 現在のバージョンが正確にコンパイルされないのはなぜですか?ここでは共分散の問題を漠然と理解していますが、説明が必要な場合は、説明できませんでした。
assertThat
メソッドをに変更することの欠点はありますMatcher<? extends T>
か?あなたがそれをした場合に壊れる他のケースはありますか?assertThat
JUnitでメソッドを一般化する意味はありますか?Matcher
JUnitのは、何もしないタイプの安全性を強制しようとする試みのような任意の一般的な、そしてただルックスに型付けされていないmatchesメソッドを呼び出しますので、としてクラスは、それを必要としていないようだMatcher
、実際にだけではないだろう一致し、テストは失敗します。安全でない操作は含まれていません(またはそのように思われます)。
参考までに、以下にJUnit実装を示し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());
}
}