【发布时间】:2009-05-22 13:48:39
【问题描述】:
给出以下示例(将 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)
然后编译工作。
所以三个问题:
- 为什么当前版本不能编译?虽然我对这里的协方差问题有模糊的了解,但如果必须,我当然无法解释。
- 将
assertThat方法更改为Matcher<? extends T>有什么缺点吗?如果您这样做,是否还有其他情况会中断? - 在 JUnit 中泛化
assertThat方法有什么意义吗?Matcher类似乎不需要它,因为 JUnit 调用了 match 方法,该方法没有使用任何泛型进行类型化,并且看起来像是在尝试强制类型安全,它什么都不做,就像 @987654332 @ 实际上不匹配,无论如何测试都会失败。不涉及不安全的操作(或者看起来如此)。
供参考,这里是assertThat的JUnit实现:
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());
}
}
【问题讨论】:
-
这个链接非常有用(泛型、继承和子类型):docs.oracle.com/javase/tutorial/java/generics/inheritance.html
-
这很奇怪,我使用的是 Java 8,
public static <T> void assertThat(T actual, Matcher<T> matcher)和public static <T> void assertThat(T result, Matcher<? extends T> matcher)编译都没有问题