Verwenden von Hamcrest Number Matchers

1. Übersicht

Hamcrest bietet statische Matcher, um die Aussagen zu Unit-Tests einfacher und lesbarer zu machen. Hier können Sie einige der verfügbaren Matcher erkunden.

In diesem Artikel werden wir uns eingehender mit den nummerbezogenen Matchern befassen.

2. Setup

Um Hamcrest zu erhalten, müssen wir unserer pom.xml nur die folgende Maven-Abhängigkeit hinzufügen :

 org.hamcrest java-hamcrest 2.0.0.0 

Die neueste Hamcrest-Version finden Sie auf Maven Central.

3. Proximity Matcher

Die ersten Matcher, die wir uns ansehen werden, prüfen, ob ein Element nahe an einem Wert von +/- einem Fehler liegt .

Formeller:

value - error <= element <= value + error

Wenn der obige Vergleich wahr ist, wird die Behauptung bestehen.

Lassen Sie es uns in Aktion sehen!

3.1. isClose With Double Values

Nehmen wir an, wir haben eine Zahl in einer Doppelvariablen namens actual gespeichert . Und wir wollen testen, ob der tatsächliche Wert nahe 1 +/- 0,5 liegt.

Das ist:

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

Erstellen wir nun einen Komponententest mit isClose matcher :

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

Da 1,3 zwischen 0,5 und 1,5 liegt, besteht der Test. Genauso können wir das negative Szenario testen:

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

Schauen wir uns nun eine ähnliche Situation mit einem anderen Variablentyp an.

3.2. isClose With BigDecimal Values

isClose ist überladen und kann wie bei doppelten Werten verwendet werden, jedoch mit BigDecimal- Objekten :

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

Bitte beachten Sie, dass der is matcher nur andere Matcher dekoriert, ohne zusätzliche Logik hinzuzufügen . Es macht nur die ganze Behauptung lesbarer.

Das war's auch schon für Proximity Matcher. Als nächstes werfen wir einen Blick auf Order Matcher.

4. Matcher bestellen

Wie der Name schon sagt, helfen diese Matcher dabei, Aussagen bezüglich der Reihenfolge zu treffen.

Es gibt fünf davon:

  • compareEqualTo
  • größer als
  • größer als oder gleich wie
  • weniger als
  • Gleich oder kleiner als

Sie sind ziemlich selbsterklärend, aber sehen wir uns einige Beispiele an.

4.1. Matcher mit ganzzahligen Werten bestellen

Das häufigste Szenario wäre die Verwendung dieser Matcher mit Zahlen .

Lassen Sie uns also einige Tests erstellen:

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

Macht Sinn, oder? Bitte beachten Sie, wie einfach es ist zu verstehen, was die Prädikate behaupten.

4.2. Matcher mit String- Werten bestellen

Obwohl das Vergleichen von Zahlen durchaus sinnvoll ist, ist es oft nützlich, andere Arten von Elementen zu vergleichen. Aus diesem Grund können Order Matcher auf jede Klasse angewendet werden, die die Comparable- Schnittstelle implementiert .

Sehen wir uns einige Beispiele mit Strings an:

@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 Arbeitsgeräte alphabetische Reihenfolge in compareTo Methode aus der Vergleichbar Schnittstelle.

Es macht also Sinn, dass das Wort „Amanda“ vor dem Wort „Benjamin“ steht.

4.3. Matcher mit LocalDate- Werten bestellen

Same as with Strings, we can compare dates. Let's take a look at the same examples we created above but using LocalDate objects:

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

It's very nice to see that the statement assertThat(today, is(lessThan(tomorrow))) is close to regular English.

4.4. Order Matchers With Custom Classes

So, why not create our own class and implement Comparable? That way, we can leverage order matchers to be used with custom order rules.

Let's start by creating a Person bean:

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

Now, let's implement 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; } }

Unsere compareTo- Implementierung vergleicht zwei Personen nach ihrem Alter. Lassen Sie uns nun ein paar neue Tests erstellen:

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

Matcher arbeiten jetzt basierend auf unserer compareTo- Logik.

5. NaN Matcher

Hamcrest bietet einen zusätzlichen Nummernvergleich, um zu definieren, ob eine Nummer tatsächlich eine Nummer ist :

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

6. Schlussfolgerungen

Wie Sie sehen können, sind Zahlenvergleiche sehr nützlich, um allgemeine Aussagen zu vereinfachen .

Darüber hinaus sind Hamcrest-Matcher im Allgemeinen selbsterklärend und leicht zu lesen .

All dies und die Möglichkeit, Matcher mit benutzerdefinierter Vergleichslogik zu kombinieren, machen sie zu einem leistungsstarken Werkzeug für die meisten Projekte da draußen.

Die vollständige Implementierung der Beispiele aus diesem Artikel finden Sie auf GitHub.