Использование hamcrest для сопоставления Карта содержит записи разных типов

Скажем, у меня есть карта:

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

Теперь я хотел бы использовать сопоставители Hamcrest для проверки значений карты. Если бы это была Map‹ String,String >, я бы сделал что-то похожее на это:

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

Однако я застрял, пытаясь использовать это с картой, где записи на карте могут быть строкой или списком значений. Это работает для первой записи:

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

Для второй записи я не могу понять, как настроить Matchers.

РЕДАКТИРОВАТЬ:

Я также пробовал это, но компилятор выдает предупреждение.

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

"Метод assertThat(T, Matcher) в типе Assert неприменим для аргументов (Map, Matcher >>>)"

(Выше было решение здесь: Hamcrest сравнить коллекции)


person acvcu    schedule 13.05.2015    source источник
comment
Какую версию Java вы используете?   -  person medvedev1088    schedule 13.05.2015
comment
версия 1.7 JDK   -  person acvcu    schedule 13.05.2015


Ответы (2)


Вы не можете сделать это элегантно с помощью Hamcrest hasEntry, поскольку он будет выполнять проверку типов, когда вы пытаетесь использовать сопоставления со списками. Самый простой вариант, я думаю, это сделать что-то вроде этого:

@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("unchecked"). Например, вы можете поместить этот статический метод в свою общую тестовую утилиту.

person medvedev1088    schedule 13.05.2015
comment
Единственное изменение, которое мне пришлось внести, это containsInAnyOrder((Object)foo2,(Object) bar2)... не уверен, почему, поскольку строки являются объектами. - person acvcu; 13.05.2015
comment
@acvcu: Это потому, что вы извлекаете элементы с карты как Object, а не String. Да, они по-прежнему являются String экземплярами, но считаются Object (аналогично Object entry = "foo";). - person Makoto; 13.05.2015

Попробуйте таким образом вы можете использовать ImmutableMap

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

Надеюсь, это сработает для вас.

person prashant thakre    schedule 13.05.2015
comment
Идея здесь в том, чтобы использовать Hamcrest, а не делать это так. Хотя этот подход будет работать без Hamcrest, я сомневаюсь, что это то, что ищет OP. - person Makoto; 13.05.2015
comment
@Makoto Я обновил свой ответ, который соответствует требованию, поскольку он основан на Hemcrest Matcher. - person prashant thakre; 13.05.2015
comment
Я обнаружил несколько проблем с этим предложением. Сначала вам нужно привести значения с помощью (Object), а во-вторых, я не понимаю, как вы пытаетесь показать коллекцию в значении для key2... - person acvcu; 13.05.2015
comment
Кажется, это работает: assertThat(map1, Matchers.‹Map‹String, Object›› equalTo(ImmutableMap.of(foo1, (Object) foo1, foo2, (Object) Arrays.asList(foo2,bar2))))); - person acvcu; 13.05.2015
comment
Любая идея, как я могу заставить это работать со случайным порядком возвращаемых фактических значений? - person acvcu; 13.05.2015
comment
@acvcu Я только что дал вам код, чтобы вы могли изменить его соответствующим образом. - person prashant thakre; 13.05.2015