web-dev-qa-db-fra.com

Comment utiliser Hamcrest pour inspecter les éléments de la carte

J'ai récemment utilisé la bibliothèque Hamcrest pour écrire des tests et j'ai réussi, mais maintenant je dois faire quelque chose de plus complexe et j'ai commencé à voir beaucoup de difficultés. Je dois inspecter et vérifier les propriétés des éléments d'une carte. Mon code de production ressemble à ceci:

    Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
    map.put("one", Arrays.asList(new MyItem("One")));
    map.put("two",  Arrays.asList(new MyItem("Two")));
    map.put("three",  Arrays.asList(new MyItem("Three")));

Je veux écrire des codes de test comme les suivants, mais cela ne se compile pas. Il semble que hasEntry de Hamcrest soit paramétré par type, tandis que hasItem et hasProperty n'attendent que Object.

    assertThat(map, Matchers.<String, List<MyItem>>hasEntry("one",  hasItem(hasProperty("name", is("One")))));

Mon IDE (Eclipse) donne ce message d'erreur: La méthode paramétrée <String, List<HamcrestTest.MyItem>>hasEntry(String, List<HamcrestTest.MyItem>) de type Matchers n'est pas applicable pour les arguments (String, Matcher<Iterable<? super Object>>) Pour une chose, je pense qu'Eclipse est confuse quant à la méthode hasEntry que je voulais utiliser, elle devrait être hasEntry(org.hamcrest.Matcher<? super K> keyMatcher, org.hamcrest.Matcher<? super V> valueMatcher), pas la hasEntry(K key, V value).

Dois-je simplement abandonner et obtenir l'élément de la carte et inspecter manuellement chaque propriété? Existe-t-il un moyen plus propre?

25
dnang

Vous pouvez simplement utiliser contains ou containsInAnyOrder. Certes, vous devrez répertorier tous les éléments dans List de cette façon, mais cela fonctionne plus proprement que hasItem:

@SuppressWarnings("unchecked")
@Test
public void mapTest() {
  Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
  map.put("one", asList(new MyItem("1"), new MyItem("one")));

  assertThat(map, hasEntry(is("one"),
                           containsInAnyOrder(hasProperty("name", is("one")),
                                              hasProperty("name", is("1")))));
}
34
t0mppa

Puisque @ t0mppa n'a pas fourni un bon exemple sur la façon d'utiliser les contains et containsInAnyOrder de Hamcrest pour cela, voici un petit quelque chose pour commencer:

Map<Integer, String> columns = new HashMap<Integer, String>();
columns.put(1, "ID");
columns.put(2, "Title");
columns.put(3, "Description");

assertThat(columns.values(), contains("ID", "Title", "Description")); // passes
assertThat(columns.values(), contains("ID", "Description", "Title")); // fails
assertThat(columns.values(), containsInAnyOrder("ID", "Description", "Title")); // passes

Notez que contrairement à hasItem et hasItems, ceux-ci ne fonctionneront que si vous leur fournissez une liste complète de toutes les valeurs que vous allez comparer. Voir Hamcrest's javadocs pour plus d'informations.

5
Priidu Neemre

Donc, pour simplifier cela, vous pouvez essayer ceci ...

assertThat((Object)map, (Matcher)Matchers.hasEntry("one",  hasItem(hasProperty("name", is("One")))));

en accédant à un type brut, vous obtiendrez un avertissement mais aucune erreur de compilation. Si j'ai utilisé cette astuce dans le passé alors que je ne veux pas m'inquiéter d'obtenir tout le casting juste pour le compilateur.

Vous pouvez également envisager d'utiliser ItIterableContainingInOrder.containingInOrder(new MyItem("One"))). Cela vérifiera la liste entière et si MyItem implémente equals alors vous n'utiliserez pas la réflexion dans vos tests.

5
John B