如何使我的自定义匹配器通用

时间:2017-05-18 14:57:12

标签: java junit hamcrest

这是一个新手问题。我正在编写一个自定义的Hamcrest匹配器,它比较两个映射并显示一个不匹配的键/值列表。该代码有效,但它仅适用于<Map<String, String>。我想使我的代码具有通用性并适用于任何Map。我尝试将String替换为Object只是为了接收错误,例如:

error: incompatible types: Map<String,String> cannot be converted to Map<Object,Object>

感谢您的帮助。

这是我的自定义匹配器:

package net.southeastwind.test;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;


public class MapEquivalent extends TypeSafeDiagnosingMatcher<Map<String, String>> {
    private Map<String, String> m_expected;

    public MapEquivalent(Map<String, String> expected) {
        m_expected = expected;
    }

    public static MapEquivalent mapEquivalent(Map<String, String> expected) {
        return new MapEquivalent(expected);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("Maps are equivalent");
    }

    @Override
    protected boolean matchesSafely(Map<String, String> actual, Description description) {
        boolean matched = true;

        Set<String> keys = new HashSet<>();
        keys.addAll(actual.keySet());
        keys.addAll(m_expected.keySet());

        for (String key: keys) {
            String expectedValue = m_expected.get(key);
            String actualValue = actual.get(key);

            if (null == expectedValue) {
                matched = false;
                description
                    .appendText("\n\t\tOnly in actual: {").appendValue(key)
                    .appendText(": ").appendValue(actualValue).appendText("}");
            } else if (null == actualValue) {
                matched = false;
                description
                    .appendText("\n\t\tOnly in expected: {").appendValue(key)
                    .appendText(": ").appendValue(expectedValue).appendText("}");
            } else if (!actualValue.equals(expectedValue)) {
                matched = false;
                description
                    .appendText("\n\t\tValues differ: ")
                    .appendText("actual={").appendValue(key).appendText(": ").appendValue(actualValue).appendText("}")
                    .appendText(", expected={").appendValue(key).appendText(": ").appendValue(expectedValue).appendText("}");

            }
        }

        return matched;
    }
}

以下是示例测试和输出:

@Test
public void compareMaps() {
    Map<String, String> expected = new HashMap<String, String>() {{
        put("alias", "haiv");
        put("uid", "501");
        put("admin", "no");
    }};

    Map<String, String> actual = new HashMap<String, String>() {{
        put("alias", "haiv");
        put("uid", "502");
        put("shell", "bash");
    }};

    assertThat("Error 6a3429f7", actual, is(mapEquivalent(expected)));
    // CustomMatchersTest > compareMaps FAILED
    //     java.lang.AssertionError: Error 6a3429f7
    //     Expected: Maps are equivalent
    //          but:
    //                 Values differ: actual={"uid": "502"}, expected={"uid": "501"}
    //                 Only in actual: {"shell": "bash"}
    //                 Only in expected: {"admin": "no"}
}

2 个答案:

答案 0 :(得分:1)

这应该让你走上正确的道路:

public class MapEquivalent<K,V> extends TypeSafeDiagnosingMatcher<Map<K, V>> {
    private Map<K, V> m_expected;

    public MapEquivalent(Map<K, V> expected) {
        m_expected = expected;
    }

    public static MapEquivalent mapEquivalent(Map<K, V> expected) {
        return new MapEquivalent(expected);
    }
    @Override
    protected boolean matchesSafely(Map<K, V> actual, Description description) 
    { /* you should get the idea now */ }
}

答案 1 :(得分:0)

以这种方式改变:

public class MapEquivalent<T, U> extends TypeSafeDiagnosingMatcher<Map<T, U>> {

    private Map<T, U> m_expected;

    public MapEquivalent(Map<T, U> expected) {
        m_expected = expected;
    }

    public static <T, U> MapEquivalent<T, U> mapEquivalent(Map<T, U> expected) {
        return new MapEquivalent<>(expected);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("Maps are equivalent");
    }

    @Override
    protected boolean matchesSafely(Map<T, U> actual, Description description) {
        boolean matched = true;

        Set<T> keys = new HashSet<>();
        keys.addAll(actual.keySet());
        keys.addAll(m_expected.keySet());

        for (T key: keys) {
            U expectedValue = m_expected.get(key);
            U actualValue = actual.get(key);

            if (null == expectedValue) {
                matched = false;
                description
                        .appendText("\n\t\tOnly in actual: {").appendValue(key)
                        .appendText(": ").appendValue(actualValue).appendText("}");
            } else if (null == actualValue) {
                matched = false;
                description
                        .appendText("\n\t\tOnly in expected: {").appendValue(key)
                        .appendText(": ").appendValue(expectedValue).appendText("}");
            } else if (!actualValue.equals(expectedValue)) {
                matched = false;
                description
                        .appendText("\n\t\tValues differ: ")
                        .appendText("actual={").appendValue(key).appendText(": ").appendValue(actualValue).appendText("}")
                        .appendText(", expected={").appendValue(key).appendText(": ").appendValue(expectedValue).appendText("}");

            }
        }

        return matched;
    }
}