如何使用Hamcrest检查Map项目

dna*_*ang 24 junit hamcrest

我最近一直在使用Hamcrest库来编写一些测试并且相当成功,但现在我需要做一些更复杂的事情并开始看到很多困难.我需要inpsect并验证Map中项目的属性.我的生产代码看起来像这样:

    Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
    map.put("one", Arrays.asList(new MyItem("One")));
    map.put("two",  Arrays.asList(new MyItem("Two")));
    map.put("three",  Arrays.asList(new MyItem("Three")));
Run Code Online (Sandbox Code Playgroud)

我想写一些测试代码,如下所示,但它不编译.看起来Hamcrest的hasEntry是类型参数化的,而hasItem和hasProperty只期望Object.

    assertThat(map, Matchers.<String, List<MyItem>>hasEntry("one",  hasItem(hasProperty("name", is("One")))));
Run Code Online (Sandbox Code Playgroud)

我的IDE(Eclipse)给出了以下错误消息:参数<String, List<HamcrestTest.MyItem>>hasEntry(String, List<HamcrestTest.MyItem>)化类型的方法Matchers不适用于参数(String, Matcher<Iterable<? super Object>>).首先,我认为Eclipse对于hasEntry我想使用哪种方法感到困惑,应该是hasEntry(org.hamcrest.Matcher<? super K> keyMatcher, org.hamcrest.Matcher<? super V> valueMatcher),而不是hasEntry(K key, V value).

我应该放弃并从地图中获取项目并手动检查每个属性吗?有更干净的方式吗?

t0m*_*ppa 32

Youu可以使用containscontainsInAnyOrder.没错,你必须以List这种方式列出所有项目,但它比hasItem以下工作更干净:

@SuppressWarnings("unchecked")
@Test
public void mapTest() {
  Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
  map.put("one", asList(new MyItem("1"), new MyItem("one")));

  assertThat(map, hasEntry(is("one"),
                           containsInAnyOrder(hasProperty("name", is("one")),
                                              hasProperty("name", is("1")))));
}
Run Code Online (Sandbox Code Playgroud)

  • 我不相信这会解决编译时错误,因为`hasEntry`将返回一个`Matcher <String,Iterable <Object >>`而不是所需的`Matcher <String,List <MyItem >>` (2认同)

Pri*_*mre 6

由于@ t0mppa没有提供关于如何使用Hamcrest的一个很好的例子,containscontainsInAnyOrder对于这一点,这里有一个小东西,让您开始:

Map<Integer, String> columns = new HashMap<Integer, String>();
columns.put(1, "ID");
columns.put(2, "Title");
columns.put(3, "Description");

assertThat(columns.values(), contains("ID", "Title", "Description")); // passes
assertThat(columns.values(), contains("ID", "Description", "Title")); // fails
assertThat(columns.values(), containsInAnyOrder("ID", "Description", "Title")); // passes
Run Code Online (Sandbox Code Playgroud)

请注意,与hasItemand 不同hasItems,这些只有在您向他们提供您将与之匹配的所有值的完整列表时才有效。有关更多信息,请参阅 Hamcrest 的javadoc


Joh*_*n B 5

所以只是为了让这个更简单,你可以尝试这个......

assertThat((Object)map, (Matcher)Matchers.hasEntry("one",  hasItem(hasProperty("name", is("One")))));
Run Code Online (Sandbox Code Playgroud)

通过转到原始类型,您将收到警告但没有编译错误.如果过去曾经使用过这个技巧,那么我不想担心所有的编译都适合编译器.

此外,您可以考虑使用ItIterableContainingInOrder.containingInOrder(new MyItem("One"))).这将验证整个列表,如果是MyItem实现,equals那么您将不会在测试中使用反射.