Hamcrest匹配器的重载冲突

匹配器IsIterableContainingInAnyOrder对静态工厂方法containsInAnyOrder有两个重载(两者都有返回类型Matcher<java.lang.Iterable> ):

  1. containsInAnyOrder(java.util.Collection<Matcher> itemMatchers)
  2. 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... 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")