web-dev-qa-db-fra.com

Comment puis-je affirmer qu'un Iterable contient des éléments avec une certaine propriété?

Supposons que je veuille tester une méthode avec cette signature:

List<MyItem> getMyItems();

Supposons que MyItem soit un Pojo ayant plusieurs propriétés, dont l’une est "name", Accessible via getName().

Tout ce qui m'importe, c'est de vérifier que le List<MyItem>, Ou n'importe quel Iterable, contient deux instances MyItem dont les propriétés "name" Ont la valeur "foo" et "bar". Si d'autres propriétés ne correspondent pas, je ne m'inquiète pas vraiment pour les besoins de ce test. Si les noms correspondent, le test est réussi.

Je voudrais que ce soit un one-liner si possible. Voici une "pseudo-syntaxe" du genre de chose que j'aimerais faire.

assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});

Hamcrest serait-il bon pour ce genre de chose? Si tel est le cas, quelle serait exactement la version la plus compliquée de ma pseudo-syntaxe ci-dessus?

93
Kevin Pauli

Merci @Razvan qui m'a dirigé dans la bonne direction. J'ai réussi à le faire en une ligne et j'ai réussi à traquer les importations pour Hamcrest 1.3.

les importations:

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;

le code:

assertThat( myClass.getMyItems(), contains(
    hasProperty("name", is("foo")), 
    hasProperty("name", is("bar"))
));
111
Kevin Pauli

Essayer:

assertThat(myClass.getMyItems(),
                          hasItem(hasProperty("YourProperty", is("YourValue"))));
47
Razvan

Ce n'est pas spécialement Hamcrest, mais je pense que cela vaut la peine de le mentionner ici. Ce que j'utilise assez souvent en Java8 est quelque chose comme:

assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));

(Modifié par la légère amélioration de Rodrigo Manyari. C'est un peu moins verbeux. Voir les commentaires.)

C'est peut-être un peu plus difficile à lire, mais j'aime bien le type et la sécurité du refactoring. C'est aussi cool pour tester plusieurs propriétés de haricots en combinaison. par exemple. avec une expression && ressemblant à Java dans le filtre lambda.

38
Mario Eis

Assertj est bon à cela.

import static org.assertj.core.api.Assertions.assertThat;

    assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");

Le grand avantage pour assertj par rapport au hamcrest est l’utilisation facile de la complétion de code.

19
Frank Neblung

AssertJ fournit une excellente fonctionnalité dans extracting(): vous pouvez passer Functions pour extraire les champs. Il fournit une vérification au moment de la compilation.
Vous pouvez également affirmer la taille d'abord facilement.

Cela donnerait:

import static org.assertj.core.api.Assertions;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName)
          .containsExactlyInAnyOrder("foo", "bar"); 

containsExactlyInAnyOrder() affirme que la liste ne contient que ces valeurs, quel que soit leur ordre.

Pour affirmer que la liste contient ces valeurs quel que soit l'ordre, mais peut également contenir d'autres valeurs, utilisez contains():

.contains("foo", "bar"); 

En remarque: pour asserter plusieurs champs à partir des éléments d'un List, AssertJ le fait en encapsulant les valeurs attendues pour chaque élément dans une fonction Tuple():

import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName, MyItem::getOtherValue)
          .containsExactlyInAnyOrder(
               Tuple("foo", "OtherValueFoo"),
               Tuple("bar", "OtherValueBar")
           ); 
9
davidxxx

Tant que votre liste est une classe concrète, vous pouvez simplement appeler la méthode contains () tant que vous avez implémenté votre méthode equals () sur MyItem.

// given 
// some input ... you to complete

// when
List<MyItems> results = service.getMyItems();

// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));

Supposons que vous ayez implémenté un constructeur qui accepte les valeurs sur lesquelles vous souhaitez affirmer. Je me rends compte que ce n'est pas sur une seule ligne, mais il est utile de savoir quelle valeur est manquante plutôt que de vérifier les deux à la fois.

5
Brad