Hamcrest匹配器的重载冲突

时间:2013-09-04 13:02:24

标签: java overloading hamcrest

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

  1. containsInAnyOrder(java.util.Collection<Matcher<? super T>> itemMatchers)
  2. containsInAnyOrder(Matcher<? super T>... itemMatchers)
  3. 现在考虑以下计划:

    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的第二个重载。

    现在,当我将断言更改为此(与documentation of the first overload中给出的示例完全匹配时):

    assertThat(Arrays.asList("foo","bar"), 
               containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar"))));
                                  ^^^^^^^^^^^^^^
    

    它不再编译,因为现在编译器将containsInAnyOrder的返回类型推断为

    Matcher<Iterable<? extends List<Matcher<String>>>>
    

    似乎编译器仍然选择第二个重载。如果它使用第一个,示例应该有效。为什么它会像这样?我怎样才能做到这一点?

    我正在使用Hamcrest 1.3和Oracle Java 1.7。

3 个答案:

答案 0 :(得分:4)

它实际上匹配两个重载方法。我不确定为什么选择第一个,但你可以提供一个提示,让它选择正确的方法。

将参数强制转换为Collection

assertThat(Arrays.asList("foo","bar"),
        containsInAnyOrder((Collection)Arrays.asList(equalTo("foo"), equalTo("bar"))));

或将泛型类型T指定为<String>(但不能使用静态导入):

assertThat(Arrays.asList("foo","bar"),
        IsIterableContainingInAnyOrder.<String>containsInAnyOrder(Arrays.asList(equalTo("foo"), equalTo("bar"))));

答案 1 :(得分:2)

当你匹配你自己的对象而不是简单的字符串时,这甚至会更难以使泛型工作得以解决。如果您正在使用问题的第一个示例中的varargs containsInAnyOrder(Matcher<? super T>... itemMatchers),那么您将获得针对varargs参数的未经检查的泛型数组警告。例如:

assertThat(myDTOList, 
    containsInAnyOrder(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2));

然后解决问题中OP所述问题的一种方法是定义您的匹配器集合,如下所示:

Collection<Matcher<? super MyDTO>> expectedMyDTOs = 
    Arrays.<Matcher<? super MyDTO>>asList(sameStateAs(expectedMyDTO1), sameStateAs(expectedMyDTO2));

// Use like this:
assertThat(myDTOList, 
    containsInAnyOrder(expectedMyDTOs);

答案 2 :(得分:2)

使用hamcrest 1.3,您可以直接使用Matchers类而不是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.<OrderValidationStep>containsInAnyOrder("foo", "bar"));
    }
}

请注意,如果您希望Type调用containsInAnyOrder,则无法使用静态导入,这样就无需添加@SuppressWarnings("unchecked")