Matchers personnalisés Hamcrest

1. Introduction

En plus des matchers intégrés, Hamcrest fournit également un support pour la création de matchers personnalisés.

Dans ce didacticiel, nous verrons de plus près comment les créer et les utiliser. Pour avoir un aperçu des correspondants disponibles, reportez-vous à cet article.

2. Configuration des correspondants personnalisés

Pour obtenir Hamcrest, nous devons ajouter la dépendance Maven suivante à notre pom.xml :

 org.hamcrest java-hamcrest 2.0.0.0 test 

La dernière version de Hamcrest est disponible sur Maven Central.

3. Présentation de TypeSafeMatcher

Avant de commencer avec nos exemples, il est important de comprendre la classe TypeSafeMatcher . Nous devrons étendre cette classe pour créer notre propre matcher.

TypeSafeMatcher est une classe abstraite, donc toutes les sous-classes doivent implémenter les méthodes suivantes:

  • matchesSafely (T t) : contient notre logique de correspondance
  • describeTo (Description description) : personnalise le message que le client recevra lorsque notre logique de correspondance n'est pas remplie

Comme nous pouvons le voir dans la première méthode, TypeSafeMatcher est paramétré, nous devrons donc déclarer un type lorsque nous l'utilisons. Ce sera le type d'objet que nous testons.

Rendons cela plus clair en regardant notre premier exemple dans la section suivante.

4. Création du onlyDigits Matcher

Pour notre premier cas d'utilisation, nous allons créer un matcher qui renvoie true si une certaine chaîne ne contient que des chiffres.

Ainsi, seuls les chiffres appliqués à «123» doivent renvoyer true tandis que « hello1 » et « bye » doivent renvoyer false.

Commençons!

4.1. Création de matcher

Pour commencer avec notre matcher, nous allons créer une classe qui étend TypeSafeMatcher :

public class IsOnlyDigits extends TypeSafeMatcher { @Override protected boolean matchesSafely(String s) { // ... } @Override public void describeTo(Description description) { // ... } }

Veuillez noter que comme l'objet que nous allons tester est un texte, nous paramétrons notre sous-classe de TypeSafeMatcher avec la classe String.

Nous sommes maintenant prêts à ajouter notre implémentation:

public class IsOnlyDigits extends TypeSafeMatcher { @Override protected boolean matchesSafely(String s) { try { Integer.parseInt(s); return true; } catch (NumberFormatException nfe){ return false; } } @Override public void describeTo(Description description) { description.appendText("only digits"); } }

Comme nous pouvons le voir, matchesSafey essaie d'analyser notre chaîne d' entrée en un entier . S'il réussit, il renvoie vrai . S'il échoue, il renvoie false . Il répond avec succès à notre cas d'utilisation.

De l'autre côté, describeTo est de joindre un texte qui représente nos attentes. Nous verrons comment cela apparaîtra ensuite lorsque nous utiliserons notre matcher.

Nous n'avons besoin que d'une chose de plus pour compléter notre matcher: une méthode statique pour y accéder , donc il se comporte comme le reste des matchers intégrés.

Donc, nous allons ajouter quelque chose comme ceci:

public static Matcher onlyDigits() { return new IsOnlyDigits(); }

Et nous avons terminé! Voyons comment utiliser ce matcher dans la section suivante.

4.2. Utilisation du matcher

Pour utiliser notre tout nouveau matcher, nous allons créer un test :

@Test public void givenAString_whenIsOnlyDigits_thenCorrect() { String digits = "1234"; assertThat(digits, onlyDigits()); }

Et c'est tout. Ce test réussira car la chaîne d' entrée ne contient que des chiffres. Rappelez - vous que, pour le rendre un peu plus lisible, nous pouvons utiliser le matcher est qui agit comme une enveloppe sur toute autre matcher :

assertThat(digits, is(onlyDigits()));

Enfin, si nous exécutions le même test mais avec l'entrée «123ABC», le message de sortie serait:

java.lang.AssertionError: Expected: only digits but: was "123ABC"

C'est là que nous voyons le texte que nous avons ajouté à la méthode describeTo . Comme nous l'avons peut-être remarqué, il est important de créer une description appropriée de ce qui est attendu dans le test.

5. divisibleBy

Alors, que faire si nous voulions créer un matcher qui définit si un nombre est divisible par un autre nombre? Pour ce scénario, nous devrons stocker l'un des paramètres quelque part.

Voyons comment nous pouvons faire cela:

public class IsDivisibleBy extends TypeSafeMatcher { private Integer divider; // constructors @Override protected boolean matchesSafely(Integer dividend) { if (divider == 0) { return false; } return ((dividend % divider) == 0); } @Override public void describeTo(Description description) { description.appendText("divisible by " + divider); } public static Matcher divisibleBy(Integer divider) { return new IsDivisibleBy(divider); } }

Assez simple, nous avons juste ajouté un nouvel attribut à notre classe et l'avons assigné pendant la construction . Ensuite, nous l'avons juste passé en paramètre à notre méthode statique:

@Test public void givenAnEvenInteger_whenDivisibleByTwo_thenCorrect() { Integer ten = 10; Integer two = 2; assertThat(ten,is(divisibleBy(two))); } @Test public void givenAnOddInteger_whenNotDivisibleByTwo_thenCorrect() { Integer eleven = 11; Integer two = 2; assertThat(eleven,is(not(divisibleBy(two)))); }

Et c'est tout! Nous avons déjà notre matcher utilisant plus d'une entrée!

6. Conclusion

Hamcrest fournit des correspondances couvrant la plupart des cas d'utilisation auxquels un développeur doit généralement faire face lors de la création d'assertions.

De plus, si un cas spécifique n'est pas couvert, Hamcrest prend également en charge la création de matchers personnalisés à utiliser dans des scénarios spécifiques - comme nous l'avons exploré ici . Ils sont simples à créer et ils sont utilisés exactement comme ceux inclus dans la bibliothèque.

Pour obtenir l'implémentation complète de ces exemples, veuillez consulter le projet GitHub.