Hamcrest匹配器的重载冲突
匹配器IsIterableContainingInAnyOrder
对静态工厂方法containsInAnyOrder
有两个重载(两者都有返回类型Matcher<java.lang.Iterable>
):
-
containsInAnyOrder(java.util.Collection<Matcher> itemMatchers)
-
containsInAnyOrder(Matcher... itemMatchers)
现在考虑以下程序:
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertThat; import java.util.Arrays; import org.junit.Test; public class SomeTest { @SuppressWarnings("unchecked") @Test public void foo() { assertThat(Arrays.asList("foo","bar"), containsInAnyOrder(equalTo("foo"), equalTo("bar"))); } }
当它作为JUnit测试执行时,它会按预期传递。 它使用上面显示的containsInAnyOrder
的第二个重载。
现在,当我将断言更改为this时(它与第一次重载的文档中给出的示例完全匹配):
assertThat(Arrays.asList("foo","bar"), containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar")))); ^^^^^^^^^^^^^^
它不再编译,因为现在编译器推断出containsInAnyOrder
的返回类型
Matcher<Iterable<? extends List<Matcher>>>
似乎编译器仍然选择第二个重载。 如果它使用了第一个,那么示例应该有效。 为什么它会像这样? 我怎样才能做到这一点?
我正在使用Hamcrest 1.3和Oracle Java 1.7。
它实际上匹配两个重载方法。 我不确定为什么选择第一个,但你可以提供一个提示,让它选择正确的方法。
通过将参数强制转换为Collection
:
assertThat(Arrays.asList("foo","bar"), containsInAnyOrder((Collection)Arrays.asList(equalTo("foo"), equalTo("bar"))));
或者通过将generics类型T指定为
(不适用于静态导入):
assertThat(Arrays.asList("foo","bar"), IsIterableContainingInAnyOrder.containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar"))));
当您匹配自己的对象而不是简单的字符串时,这甚至会更难以使generics工作。 如果你在问题的第一个例子中使用varargs containsInAnyOrder(Matcher super T>... itemMatchers)
,你将获得一个针对varargs参数警告的未经检查的generics数组创建 。 例如:
assertThat(myDTOList, containsInAnyOrder(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2));
解决问题中OP所述问题的一种方法是定义您的匹配器集合,如下所示:
Collection> expectedMyDTOs = Arrays.>asList(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2)); // Use like this: assertThat(myDTOList, containsInAnyOrder(expectedMyDTOs);
使用hamcrest 1.3,您可以直接使用IsIterableContainingInAnyOrder
类而不是IsIterableContainingInAnyOrder
,如@eee所述。 Matchers实际上只是为你调用IsIterableContainingInAnyOrder。
import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertThat; import org.hamcrest.Matchers; import java.util.Arrays; import org.junit.Test; public class SomeTest { @Test public void foo() { assertThat(Arrays.asList("foo","bar"), Matchers.containsInAnyOrder("foo", "bar")); } }
请注意,如果要Type
对containsInAnyOrder的调用,则无法使用静态导入,这样就无需添加@SuppressWarnings("unchecked")