Utilisation des numéroteurs Hamcrest

1. Vue d'ensemble

Hamcrest fournit des correspondants statiques pour aider à rendre les assertions de test unitaire plus simples et plus lisibles. Vous pouvez commencer à explorer certains des correspondants disponibles ici.

Dans cet article, nous allons approfondir les correspondances liées aux nombres.

2. Configuration

Pour obtenir Hamcrest, il suffit d'ajouter la dépendance Maven suivante à notre pom.xml :

 org.hamcrest java-hamcrest 2.0.0.0 

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

3. Correspondants de proximité

Le premier ensemble de matchers que nous allons examiner sont ceux qui vérifient si un élément est proche d'une valeur +/- une erreur .

Plus formellement:

value - error <= element <= value + error

Si la comparaison ci-dessus est vraie, l'assertion passera.

Voyons-le en action!

3.1. isClose avec des valeurs doubles

Disons que nous avons un nombre stocké dans une variable double appelée réelle. Et nous voulons tester si le réel est proche de 1 +/- 0,5.

C'est:

1 - 0.5 <= actual <= 1 + 0.5 0.5 <= actual <= 1.5

Créons maintenant un test unitaire à l'aide du matcher isClose :

@Test public void givenADouble_whenCloseTo_thenCorrect() { double actual = 1.3; double operand = 1; double error = 0.5; assertThat(actual, closeTo(operand, error)); }

Comme 1,3 est compris entre 0,5 et 1,5, le test réussira. De la même manière, on peut tester le scénario négatif:

@Test public void givenADouble_whenNotCloseTo_thenCorrect() { double actual = 1.6; double operand = 1; double error = 0.5; assertThat(actual, not(closeTo(operand, error))); }

Examinons maintenant une situation similaire avec un type de variables différent.

3.2. isClose avec des valeurs BigDecimal

isClose est surchargé et peut être utilisé de la même manière qu'avec des valeurs doubles, mais avec des objets BigDecimal :

@Test public void givenABigDecimal_whenCloseTo_thenCorrect() { BigDecimal actual = new BigDecimal("1.0003"); BigDecimal operand = new BigDecimal("1"); BigDecimal error = new BigDecimal("0.0005"); assertThat(actual, is(closeTo(operand, error))); } @Test public void givenABigDecimal_whenNotCloseTo_thenCorrect() { BigDecimal actual = new BigDecimal("1.0006"); BigDecimal operand = new BigDecimal("1"); BigDecimal error = new BigDecimal("0.0005"); assertThat(actual, is(not(closeTo(operand, error)))); }

Veuillez noter que le matcher is décore uniquement les autres matchers sans ajouter de logique supplémentaire . Cela rend simplement l'assertion plus lisible.

C'est à peu près tout pour les matchers de proximité. Ensuite, nous examinerons les correspondances d'ordre.

4. Correspondants d'ordre

Comme leur nom l'indique, ces correspondants aident à faire des affirmations concernant la commande.

Il y en a cinq:

  • compareEqualTo
  • plus grand que
  • Plus grand ou égal à
  • moins que
  • inférieur ou égal à

Ils sont assez explicites, mais voyons quelques exemples.

4.1. Correspondants d'ordres avec aleurs V entières

Le scénario le plus courant consisterait à utiliser ces apparieurs avec des nombres .

Alors, allons-y et créons quelques tests:

@Test public void given5_whenComparesEqualTo5_thenCorrect() { Integer five = 5; assertThat(five, comparesEqualTo(five)); } @Test public void given5_whenNotComparesEqualTo7_thenCorrect() { Integer seven = 7; Integer five = 5; assertThat(five, not(comparesEqualTo(seven))); } @Test public void given7_whenGreaterThan5_thenCorrect() { Integer seven = 7; Integer five = 5; assertThat(seven, is(greaterThan(five))); } @Test public void given7_whenGreaterThanOrEqualTo5_thenCorrect() { Integer seven = 7; Integer five = 5; assertThat(seven, is(greaterThanOrEqualTo(five))); } @Test public void given5_whenGreaterThanOrEqualTo5_thenCorrect() { Integer five = 5; assertThat(five, is(greaterThanOrEqualTo(five))); } @Test public void given3_whenLessThan5_thenCorrect() { Integer three = 3; Integer five = 5; assertThat(three, is(lessThan(five))); } @Test public void given3_whenLessThanOrEqualTo5_thenCorrect() { Integer three = 3; Integer five = 5; assertThat(three, is(lessThanOrEqualTo(five))); } @Test public void given5_whenLessThanOrEqualTo5_thenCorrect() { Integer five = 5; assertThat(five, is(lessThanOrEqualTo(five))); }

Cela a du sens, non? Veuillez noter qu'il est simple de comprendre ce que les prédicats affirment.

4.2. Correspondants d'ordre avec des valeurs de chaîne

Même si comparer des nombres a tout son sens, il est souvent utile de comparer d'autres types d'éléments. C'est pourquoi les correspondances d'ordre peuvent être appliquées à n'importe quelle classe qui implémente l' interface Comparable .

Voyons quelques exemples avec des chaînes:

@Test public void givenBenjamin_whenGreaterThanAmanda_thenCorrect() { String amanda = "Amanda"; String benjamin = "Benjamin"; assertThat(benjamin, is(greaterThan(amanda))); } @Test public void givenAmanda_whenLessThanBenajmin_thenCorrect() { String amanda = "Amanda"; String benjamin = "Benjamin"; assertThat(amanda, is(lessThan(benjamin))); }

String implémente l'ordre alphabétique dans la méthode compareTo à partir de l' interface Comparable .

Il est donc logique que le mot «Amanda» précède le mot «Benjamin».

4.3. Correspondants d'ordre avec des valeurs LocalDate

Comme pour les chaînes , nous pouvons comparer les dates. Jetons un coup d'œil aux mêmes exemples que nous avons créés ci-dessus, mais en utilisant des objets LocalDate :

@Test public void givenToday_whenGreaterThanYesterday_thenCorrect() { LocalDate today = LocalDate.now(); LocalDate yesterday = today.minusDays(1); assertThat(today, is(greaterThan(yesterday))); } @Test public void givenToday_whenLessThanTomorrow_thenCorrect() { LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plusDays(1); assertThat(today, is(lessThan(tomorrow))); }

C'est très agréable de voir que la déclaration affirmerThat (today, is (lessThan (tomorrow))) est proche de l'anglais ordinaire.

4.4. Pour Matchers avec classe personnalisée es

Alors, pourquoi ne pas créer notre propre classe et implémenter Comparable? De cette façon, nous pouvons exploiter les correspondances de commande à utiliser avec des règles de commande personnalisées .

Commençons par créer un bean Person :

public class Person { String name; int age; // standard constructor, getters and setters }

Maintenant, implémentons Comparable :

public class Person implements Comparable { // ... @Override public int compareTo(Person o) { if (this.age == o.getAge()) return 0; if (this.age > o.getAge()) return 1; else return -1; } }

Notre implémentation compareTo compare deux personnes par leur âge. Créons maintenant quelques nouveaux tests:

@Test public void givenAmanda_whenOlderThanBenjamin_thenCorrect() { Person amanda = new Person("Amanda", 20); Person benjamin = new Person("Benjamin", 18); assertThat(amanda, is(greaterThan(benjamin))); } @Test public void givenBenjamin_whenYoungerThanAmanda_thenCorrect() { Person amanda = new Person("Amanda", 20); Person benjamin = new Person("Benjamin", 18); assertThat(benjamin, is(lessThan(amanda))); }

Les matchers fonctionneront désormais selon notre logique compareTo .

5. NaN Matcher

Hamcrest fournit un matcher de nombre supplémentaire pour définir si un nombre est réellement, pas un nombre :

@Test public void givenNaN_whenIsNotANumber_thenCorrect() { double zero = 0d; assertThat(zero / zero, is(notANumber())); }

6. Conclusions

Comme vous pouvez le voir, les apparieurs de nombres sont très utiles pour simplifier les assertions courantes .

De plus, les matchers Hamcrest en général, sont explicites et faciles à lire .

Tout cela, ainsi que la possibilité de combiner des matchers avec une logique de comparaison personnalisée, en font un outil puissant pour la plupart des projets.

L'implémentation complète des exemples de cet article est disponible à l'adresse over sur GitHub.