web-dev-qa-db-fra.com

Égalité des cartes avec Hamcrest

J'aimerais utiliser hamcrest pour affirmer que deux cartes sont égales, c'est-à-dire qu'elles ont le même jeu de clés pointant vers les mêmes valeurs.

Ma meilleure hypothèse actuelle est:

assertThat( affA.entrySet(), hasItems( affB.entrySet() );

qui donne:

La méthode assertThat (T, Matcher) dans le type Assert n'est pas applicable pour les arguments (Set>, Matcher >>>)

J'ai également examiné les variantes de includesAll et quelques autres fournies par les packages hamcrest. Est-ce que quelqu'un peut-il me montrer la bonne direction? Ou dois-je écrire un matcher personnalisé?

44
mo-seph

Le chemin le plus court que j'ai trouvé est deux déclarations:

assertThat( affA.entrySet(), everyItem(isIn(affB.entrySet())));
assertThat( affB.entrySet(), everyItem(isIn(affA.entrySet())));

Mais vous pouvez probablement aussi faire:

assertThat(affA.entrySet(), equalTo(affB.entrySet()));

en fonction des implémentations des cartes.

UPDATE: il existe en réalité une instruction qui fonctionne indépendamment des types de collection:

assertThat(affA.entrySet, both(everyItem(isIn(affB.entrySet()))).and(containsInAnyOrder(affB.entrySet())));
47
Hans-Peter Störr

Parfois, Map.equals() est suffisant. Mais parfois, vous ne savez pas que les types de Maps sont renvoyés par le code soumis à des tests. Par conséquent, vous ne savez pas si .equals() comparera correctement la mappe de type inconnu renvoyée par le code à la mappe construite par vous. Ou vous ne voulez pas lier votre code avec de tels tests.

De plus, construire une carte séparément pour comparer le résultat avec celui-ci est un IMHO pas très élégant:

Map<MyKey, MyValue> actual = methodUnderTest();

Map<MyKey, MyValue> expected = new HashMap<MyKey, MyValue>();
expected.put(new MyKey(1), new MyValue(10));
expected.put(new MyKey(2), new MyValue(20));
expected.put(new MyKey(3), new MyValue(30));
assertThat(actual, equalTo(expected));

Je préfère utiliser des machers:

import static org.hamcrest.Matchers.hasEntry;

Map<MyKey, MyValue> actual = methodUnderTest();
assertThat(actual, allOf(
                      hasSize(3), // make sure there are no extra key/value pairs in map
                      hasEntry(new MyKey(1), new MyValue(10)),
                      hasEntry(new MyKey(2), new MyValue(20)),
                      hasEntry(new MyKey(3), new MyValue(30))
));

Je dois définir moi-même hasSize():

public static <K, V> Matcher<Map<K, V>> hasSize(final int size) {
    return new TypeSafeMatcher<Map<K, V>>() {
        @Override
        public boolean matchesSafely(Map<K, V> kvMap) {
            return kvMap.size() == size;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText(" has ").appendValue(size).appendText(" key/value pairs");
        }
    };
}

Et il existe une autre variante de hasEntry() qui prend les correspondants comme paramètres au lieu des valeurs exactes de clé et de valeur. Cela peut être utile si vous avez besoin de quelque chose d'autre que le test d'égalité de chaque clé et valeur.

35
Alexey Tigarev

Une autre option disponible consiste à utiliser l’extension Cirneco pour Hamcrest. Il a hasSameKeySet() (ainsi que d'autres correspondants pour les "collections" de goyave) . Selon votre exemple, ce sera:

assertThat(affA, hasSameKeySet(affB));

Vous pouvez utiliser la dépendance suivante pour un projet basé sur JDK7:

<dependency>
  <groupId>it.ozimov</groupId>
  <artifactId>Java7-hamcrest-matchers</artifactId>
  <version>0.7.0</version>
</dependency>

ou les suivants si vous utilisez JDK8 ou supérieur:

<dependency>
  <groupId>it.ozimov</groupId>
  <artifactId>Java8-hamcrest-matchers</artifactId>
  <version>0.7.0</version>
</dependency>
2
JeanValjean

Je préfère utiliser Guava ImmutableMap . Ils supportent Map.equals() et sont faciles à construire. La seule astuce consiste à spécifier explicitement les paramètres de type, puisque hamcrest assumera le type ImmutableMap.

assertThat( actualValue,
            Matchers.<Map<String, String>>equalTo( ImmutableMap.of(
                "key1", "value",
                "key2", "other-value"
) ) );
2
Huuu

Cela fonctionne comme un charme et ne nécessite pas deux affirmations comme la réponse acceptée.

assertThat( actualData.entrySet().toArray(), 
    arrayContainingInAnyOrder(expectedData.entrySet().toArray()) );
0
Bryan Correll

Si vous avez besoin de comparer un ensemble de résultats avec les attentes et si vous choisissez d'utiliser assertj library, vous pouvez le faire: 

// put set of expected values by your test keys
Map<K, V> expectations = ...;

// for each test key get result
Map<K, V> results = expectations.keySet().stream().collect(toMap(k -> k, k -> getYourProductionResult(k)));

assertThat(results).containsAllEntriesOf(expectations);

Notez que containsAllEntriesOf ne compare pas les cartes pour l’égalité. Si votre code de production renvoie en réalité un Map<K, V>, vous pouvez ajouter une vérification des clés assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray()); .

0
Andrii Karaivanskyi

Une méthode assez simple consiste à utiliser une méthode utilitaire issue de la classe com.google.common.collect.Maps de Guava.

assertThat(Maps.difference(map1,map2).areEqual(),is(true));
0

Hamcrest a maintenant une Matcher pour la collection de taille.

org.hamcrest.collection.IsCollectionWithSize

0
ZPalazov