使用 hamcrest 匹配 Map 包含不同类型的条目

2022-09-04 03:51:08

假设我有一张地图:

Map<String,Object> map1 = new HashMap<String,Object>();
map1.put("foo1","foo1");
map1.put("foo2", Arrays.asList("foo2","bar2"));

现在我想使用Hamcrest匹配器来验证Map的值。如果这是一个Map< String,String >我会做类似这样的事情:

assertThat(map1, hasEntry("foo1", "foo1"));

但是,在尝试将其与Map一起使用时,我遇到了困难,其中Map中的条目可能是字符串或值列表。这适用于第一个条目:

assertThat(map1, hasEntry("foo1", (Object)"foo1"));

对于第二个条目,我不知道如何设置匹配器。

编辑:

我也尝试过,但它会产生编译器警告。

assertThat(
            map1,
            hasEntry(
                    "foo2",
                    contains(hasProperty("name", is("foo2")),
                            hasProperty("name", is("bar2")))));

“Assert 类型中的方法 assertThat(T, Matcher) 不适用于参数(Map、Matcher>>>)”

(以上是这里的解决方案:Hamcrest比较系列 )


答案 1

你不能用Hamcrest优雅地做到这一点,因为当你尝试使用匹配器而不是列表时,它会进行类型检查。hasEntry

https://github.com/hamcrest/JavaHamcrest/issues/388 上有一个功能请求

我认为最简单的选择是做这样的事情:

@Test
public void test() {
    Map<String, Object> map1 = new HashMap<>();
    map1.put("foo1", "foo1");
    map1.put("foo2", Arrays.asList("foo2", "bar2"));

    assertThat(map1, hasEntry("foo1", "foo1"));
    assertThat(map1, hasListEntry(is("foo2"), containsInAnyOrder("foo2", "bar2")));
}

@SuppressWarnings("unchecked")
public static org.hamcrest.Matcher<java.util.Map<String, Object>> hasListEntry(org.hamcrest.Matcher<String> keyMatcher, org.hamcrest.Matcher<java.lang.Iterable<?>> valueMatcher) {
    Matcher mapMatcher = org.hamcrest.collection.IsMapContaining.<String, List<?>>hasEntry(keyMatcher, valueMatcher);
    return mapMatcher;
}

hasListEntry这里只是为了防止编译器错误。它执行未选中的分配,这就是为什么您需要@SuppressWarnings(“未选中”)。例如,您可以将此静态方法放在常用测试工具中。


答案 2

尝试以这种方式,你可以使用不可变的地图

 assertThat( actualValue,
            Matchers.<Map<String, Object>>equalTo( ImmutableMap.of(
                "key1", "value",
                "key2", "arrayrelated values"
) ) );

希望它能为你工作。


推荐