Utilizzo di Hamcrest Number Matchers

1. Panoramica

Hamcrest fornisce abbinamenti statici per aiutare a rendere le asserzioni dei test unitari più semplici e leggibili. Puoi iniziare a esplorare alcuni degli abbinamenti disponibili qui.

In questo articolo, approfondiremo gli abbinamenti relativi ai numeri.

2. Configurazione

Per ottenere Hamcrest, dobbiamo solo aggiungere la seguente dipendenza Maven al nostro pom.xml :

 org.hamcrest java-hamcrest 2.0.0.0 

L'ultima versione di Hamcrest può essere trovata su Maven Central.

3. Matcher di prossimità

La prima serie di abbinamenti a cui daremo un'occhiata sono quelli che controllano se qualche elemento è vicino a un valore +/- un errore .

Più formalmente:

value - error <= element <= value + error

Se il confronto di cui sopra è vero, l'affermazione passerà.

Vediamolo in azione!

3.1. isClose With Double Values

Supponiamo di avere un numero memorizzato in una doppia variabile chiamata effettiva. Inoltre, vogliamo verificare se il valore effettivo è vicino a 1 +/- 0,5.

Questo è:

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

Ora creiamo uno unit test usando isClose matcher:

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

Poiché 1,3 è compreso tra 0,5 e 1,5, il test passerà. Allo stesso modo, possiamo testare lo scenario negativo:

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

Ora, diamo un'occhiata a una situazione simile con un diverso tipo di variabili.

3.2. isClose con valori BigDecimal

isClose è sovraccarico e può essere utilizzato come con valori double, ma con oggetti 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)))); }

Si ricorda che l' è matcher unico decora altri matchers senza l'aggiunta di logica in più . Rende solo l'intera affermazione più leggibile.

Questo è tutto per i matcher di prossimità. Successivamente, daremo un'occhiata agli abbinamenti degli ordini.

4. Ordina Matchers

Come dice il loro nome, questi abbinatori aiutano a fare affermazioni sull'ordine.

Ce ne sono cinque:

  • comparesEqualTo
  • più grande di
  • maggiore o uguale a
  • meno di
  • minore o uguale a

Sono praticamente autoesplicativi, ma vediamo alcuni esempi.

4.1. Order Matchers With Integer V alues

Lo scenario più comune sarebbe usare questi abbinatori con i numeri .

Quindi, andiamo avanti e creiamo alcuni test:

@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))); }

Ha senso, vero? Si noti quanto sia semplice capire cosa affermano i predicati.

4.2. Ordina matcher con valori stringa

Anche se confrontare i numeri ha perfettamente senso, molte volte è utile confrontare altri tipi di elementi. Ecco perché gli abbinamenti degli ordini possono essere applicati a qualsiasi classe che implementa l' interfaccia Comparable .

Vediamo alcuni esempi con le stringhe:

@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 implementa l'ordine alfabetico nel metodo compareTo dall'interfaccia Comparable .

Quindi, ha senso che la parola "Amanda" venga prima della parola "Benjamin".

4.3. Ordina corrispondenze con valori LocalDate

Come con le stringhe , possiamo confrontare le date. Diamo un'occhiata agli stessi esempi che abbiamo creato sopra ma utilizzando oggetti 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))); }

È molto bello vedere che l'affermazione assertThat (today, is (lessThan (tomorrow))) è simile all'inglese normale.

4.4. Ordina Matcher con classi personalizzate es

Quindi, perché non creare la nostra classe e implementare Comparable? In questo modo, possiamo sfruttare gli abbinamenti degli ordini da utilizzare con le regole degli ordini personalizzate .

Cominciamo creando un bean Person :

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

Ora, implementiamo 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; } }

La nostra implementazione compareTo mette a confronto due persone in base alla loro età. Creiamo ora un paio di nuovi test:

@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))); }

I matcher ora funzioneranno in base alla nostra logica compareTo .

5. NaN Matcher

Hamcrest fornisce un abbinatore di numeri in più per definire se un numero è effettivamente, non un numero :

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

6. Conclusioni

Come puoi vedere, gli abbinamenti di numeri sono molto utili per semplificare le asserzioni comuni .

Inoltre, i matcher di Hamcrest in generale sono autoesplicativi e facili da leggere .

Tutto questo, oltre alla possibilità di combinare abbinamenti con logica di confronto personalizzata, li rende uno strumento potente per la maggior parte dei progetti.

L'implementazione completa degli esempi di questo articolo può essere trovata su GitHub.