【问题标题】:How to assert Map contains Map with entry如何断言 Map 包含带有条目的 Map
【发布时间】:2015-07-20 18:31:02
【问题描述】:

我有一个需要检查嵌套映射值的单元测试。我可以通过拉出条目并匹配底层Map 来使我的断言起作用,但我正在寻找一种清晰的方法来显示断言正在做什么。这是一个非常简化的测试:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class MapContainsMapTest {
    @Test
    public void testMapHasMap() {
        Map<String, Object> outerMap = new HashMap<String, Object>();
        Map<String, Object> nestedMap = new HashMap<String, Object>();
        nestedMap.put("foo", "bar");
        outerMap.put("nested", nestedMap);

        // works but murky
        assertThat((Map<String, Object>) outerMap.get("nested"), hasEntry("foo", "bar"));
        // fails but clear
        assertThat(outerMap, hasEntry("nested", hasEntry("foo", "bar")));
    }
}

似乎问题是使用hasEntry(K key, V value) 比较外部地图,而我想要使用的是hasEntry(Matcher&lt;? super K&gt; keyMatcher, Matcher&lt;? super V&gt; valueMatcher)。我不确定如何强制断言使用第二种形式。

提前致谢。

【问题讨论】:

  • "似乎问题是正在使用 ..." 比较外部地图。例如,hasEntry(is("key"), is("value")) 会导致使用第二种形式。也许您可以使用equalTo 匹配器代替is,但无论哪种方式,可读性都超出了窗口。
  • 问题出在外部测试上,所以我需要equalTo("nested")... 之类的东西,但除非我将外部地图类型更改为Map&lt;String, Map&lt;String,Object&gt;&gt;

标签: java junit hamcrest


【解决方案1】:

如果您只想将 Map&lt;String, Object&gt; 作为值放入您的 outerMap 中,请相应地调整声明。然后就可以了

@Test
public void testMapHasMap() {
    Map<String, Map<String, Object>> outerMap = new HashMap<>();
    Map<String, Object> nestedMap = new HashMap<String, Object>();
    nestedMap.put("foo", "bar");
    outerMap.put("nested", nestedMap);

    Object value = "bar";
    assertThat(outerMap, hasEntry(equalTo("nested"), hasEntry("foo", value)));  
}

Object value = "bar"; 是编译原因所必需的。或者你可以使用

assertThat(outerMap,
   hasEntry(equalTo("nested"), Matchers.<String, Object> hasEntry("foo", "bar")));

【讨论】:

  • 我的示例是我的测试的简化版本,其中 outerMap 是一个 JSON 对象,其中并非所有条目都是地图,因此我必须保持地图声明的原样。
【解决方案2】:

我可能会为此扩展一个新的 Matcher,类似的东西(注意,NPE 潜伏):

class SubMapMatcher extends BaseMatcher<Map<?,?>> {

private Object key;
private Object subMapKey;
private Object subMapValue;

public SubMapMatcher(Object key, Object subMapKey, Object subMapValue) {
    super();
    this.key = key;
    this.subMapKey = subMapKey;
    this.subMapValue = subMapValue;
}

@Override
public boolean matches(Object item) {

    Map<?,?> map = (Map<?,?>)item;

    if (!map.containsKey(key)) {
        return false;
    }

    Object o = map.get(key);

    if (!(o instanceof Map<?,?>)) {
        return false;
    }

    Map<?,?> subMap = (Map<?,?>)o;
    return subMap.containsKey(subMapKey) && subMap.get(subMapKey).equals(subMapValue);
}

@Override
public void describeTo(Description description) {
    description.appendText(String.format("contains %s -> %s : %s", key, subMapKey, subMapValue));
}

public static SubMapMatcher containsSubMapWithKeyValue(String key, String subMapKey, String subMapValue) {
    return new SubMapMatcher(key, subMapKey, subMapValue);
}

}

【讨论】:

  • 谢谢,这个答案有效。但是,我想我想看看是否可以扩展它以允许任何级别的嵌套。
  • 听起来很简单,您可以简单地使用像Object value, String... keys 这样的签名。然后遍历键,获取子映射,直到到达最后一个(或偶然发现 null 或非映射作为您的值)并检查该值。例如containsValueInSubMap( someValue, map0Key, map1Key, map2Key); 当然,我个人不建议将标准 Map 用于键 ->“值或子图”映射,而是更具体的东西也允许具有通用值类型(具有子图和值的映射是实际上是一棵树,应该很容易找到东西)。
【解决方案3】:

如果您将 outerMap 声明为 Map&lt;String, Map&lt;String, Object&gt;&gt;,则不需要丑陋的演员表。像这样:

public class MapContainsMapTest {

    @Test
    public void testMapHasMap() {
        Map<String, Map<String, Object>> outerMap = new HashMap<>();
        Map<String, Object> nestedMap = new HashMap<>();
        nestedMap.put("foo", "bar");
        outerMap.put("nested", nestedMap);

        assertThat(outerMap.get("nested"), hasEntry("foo", "bar"));
    }
}

【讨论】:

  • @DanGetz 如果我删除演员表,它不会编译,outerMap 必须声明为 Map>。
  • 我的示例是我的测试的简化版本,其中 outerMap 是一个 JSON 对象,其中并非所有条目都是地图,因此我必须保持地图声明的原样。
【解决方案4】:

试试这样:

        assertThat(nestedMap).contains(Map.entry("foo", "bar"));
        assertThat(outerMap).contains(Map.entry("nested", nestedMap));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-01
    • 2011-10-09
    • 2020-08-04
    • 2019-11-20
    • 1970-01-01
    • 2015-07-25
    • 2018-12-19
    • 1970-01-01
    相关资源
    最近更新 更多