使用Mockito,如何与地图的键值对匹配? [英] Using Mockito, how do I match against the key-value pair of a map?

查看:133
本文介绍了使用Mockito,如何与地图的键值对匹配?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要根据特定的键值从模拟对象发送特定的值.

I need to send a specific value from a mock object based on a specific key value.

从具体类中来:

map.put("xpath", "PRICE");
search(map);

从测试用例开始:

IOurXMLDocument mock = mock(IOurXMLDocument.class);
when(mock.search(.....need help here).thenReturn("$100.00");

如何模拟此键值对的此方法调用?

How do I mock this method call for this key value pair?

推荐答案

我发现这试图解决创建带有Map参数的Mockito存根的类似问题.我不想为有问题的地图编写自定义匹配器,然后找到了一个更优雅的解决方案:在 hamcrest-library ,带有模仿者的argThat:

I found this trying to solve a similar issue creating a Mockito stub with a Map parameter. I didn't want to write a custom matcher for the Map in question and then I found a more elegant solution: use the additional matchers in hamcrest-library with mockito's argThat:

when(mock.search(argThat(hasEntry("xpath", "PRICE"))).thenReturn("$100.00");

如果您需要检查多个条目,则可以使用其他Hamcrest礼物:

If you need to check against multiple entries then you can use other hamcrest goodies:

when(mock.search(argThat(allOf(hasEntry("xpath", "PRICE"), hasEntry("otherKey", "otherValue")))).thenReturn("$100.00");

对于非平凡的地图,这开始变得冗长了,所以我最终提取了一些方法来收集条目匹配器,并将其粘贴在我们的TestUtils中:

This starts to get long with non-trivial maps, so I ended up extracting methods to collect the entry matchers and stuck them in our TestUtils:

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.hasEntry;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hamcrest.Matcher;
---------------------------------
public static <K, V> Matcher<Map<K, V>> matchesEntriesIn(Map<K, V> map) {
    return allOf(buildMatcherArray(map));
}

public static <K, V> Matcher<Map<K, V>> matchesAnyEntryIn(Map<K, V> map) {
    return anyOf(buildMatcherArray(map));
}

@SuppressWarnings("unchecked")
private static <K, V> Matcher<Map<? extends K, ? extends V>>[] buildMatcherArray(Map<K, V> map) {
    List<Matcher<Map<? extends K, ? extends V>>> entries = new ArrayList<Matcher<Map<? extends K, ? extends V>>>();
    for (K key : map.keySet()) {
        entries.add(hasEntry(key, map.get(key)));
    }
    return entries.toArray(new Matcher[entries.size()]);
}

所以我只剩下:

when(mock.search(argThat(matchesEntriesIn(map))).thenReturn("$100.00");
when(mock.search(argThat(matchesAnyEntryIn(map))).thenReturn("$100.00");

与泛型相关联的是一些难看的东西,我抑制了一个警告,但是至少它是DRY并且隐藏在TestUtil中.

There's some ugliness associated with the generics and I'm suppressing one warning, but at least it's DRY and hidden away in the TestUtil.

最后一个提示,请注意嵌入式hamcrest JUnit 4.10 中的问题.对于Maven,我建议先导入hamcrest-library,然后再导入JUnit 4.11(现在为4.12),并从JUnit中排除hamcrest-core,以防万一:

One last note, beware the embedded hamcrest issues in JUnit 4.10. With Maven, I recommend importing hamcrest-library first and then JUnit 4.11 (now 4.12) and exclude hamcrest-core from JUnit just for good measure:

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>


2017年9月1日-根据部分评论,我更新了答案以显示我的Mockito依赖关系,我在测试实用程序中的导入以及一个从今天开始运行绿色的junit:


Sept 1, 2017 - Per some of the comments, I updated my answer to show my Mockito dependency, my imports in the test util, and a junit that is running green as of today:

import static blah.tool.testutil.TestUtil.matchesAnyEntryIn;
import static blah.tool.testutil.TestUtil.matchesEntriesIn;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import org.junit.Test;

public class TestUtilTest {

    @Test
    public void test() {
        Map<Integer, String> expected = new HashMap<Integer, String>();
        expected.put(1, "One");
        expected.put(3, "Three");

        Map<Integer, String> actual = new HashMap<Integer, String>();
        actual.put(1, "One");
        actual.put(2, "Two");

        assertThat(actual, matchesAnyEntryIn(expected));

        expected.remove(3);
        expected.put(2, "Two");
        assertThat(actual, matchesEntriesIn(expected));
    }

    @Test
    public void mockitoTest() {
        SystemUnderTest sut = mock(SystemUnderTest.class);
        Map<Integer, String> expected = new HashMap<Integer, String>();
        expected.put(1, "One");
        expected.put(3, "Three");

        Map<Integer, String> actual = new HashMap<Integer, String>();
        actual.put(1, "One");

        when(sut.search(argThat(matchesAnyEntryIn(expected)))).thenReturn("Response");
        assertThat(sut.search(actual), is("Response"));
    }

    protected class SystemUnderTest {
        // We don't really care what this does
        public String search(Map<Integer, String> map) {
            if (map == null) return null;
            return map.get(0);
        }
    }
}

这篇关于使用Mockito,如何与地图的键值对匹配?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆