Testen met Hamcrest

1. Overzicht

Hamcrest is het bekende framework dat wordt gebruikt voor unit testing in het Java-ecosysteem. Het is gebundeld in JUnit en simpel gezegd, het gebruikt bestaande predikaten - matcher-klassen genaamd - voor het doen van beweringen.

In deze tutorial zullen we dat doen verken de Hamcrest API en leer hoe u er gebruik van kunt maken om nettere en intuïtievere unit-tests voor onze software te schrijven.

2. Hamcrest-opstelling

We kunnen gebruiken Hamcrest met maven door de volgende afhankelijkheid toe te voegen aan onze pom.xml het dossier:

 org.hamcrest hamcrest-all 1.3 

De laatste versie van deze bibliotheek is hier altijd te vinden.

3. Een voorbeeldtest

Hamcrest wordt vaak gebruikt met junit en andere toetsingskaders voor het doen van beweringen. Specifiek, in plaats van te gebruiken junit‘Is talrijk beweren methoden gebruiken we alleen de API's single beweren dat verklaring met de juiste matchers.

Laten we eens kijken naar een voorbeeld dat er twee test Draads voor gelijkheid, ongeacht het geval. Dit zou ons een duidelijk idee moeten geven over hoe Hamcrest past in een testmethode:

openbare klasse StringMatcherTest {@Test openbare leegte gegeven2Strings_whenEqual_thenCorrect () {String a = "foo"; String b = "FOO"; assertThat (a, equalToIgnoringCase (b)); }}

In de volgende secties zullen we een aantal andere veel voorkomende matchers bekijken Hamcrest aanbiedingen.

4. Het Voorwerp Matcher

Hamcrest biedt matchers voor het doen van beweringen over willekeurige Java-objecten.

Om te beweren dat het toString methode van een Voorwerp geeft een opgegeven Draad:

@Test openbare ongeldig gegevenBean_whenToStringReturnsRequiredString_thenCorrect () {Persoon persoon = nieuwe persoon ("Barrack", "Washington"); String str = person.toString (); assertThat (person, hasToString (str)); }

We kunnen ook controleren of de ene klasse een subklasse is van een andere:

@Test openbare ongeldig gegeven2Classes_whenOneInheritsFromOther_thenCorrect () {assertThat (Cat.class, typeCompatibleWith (Animal.class)); }}

5. De bonenmatcher

We kunnen gebruiken Hamcrest‘S Bean-matcher om eigenschappen van een Java-bean te inspecteren.

Veronderstel het volgende Persoon Boon:

openbare klasse Persoon {Stringnaam; String adres; publieke persoon (String personName, String personAddress) {name = personName; address = personAddress; }}

We kunnen controleren of de boon de eigenschap heeft, naam zo:

@Test openbare ongeldig gegevenBean_whenHasValue_thenCorrect () {Persoon persoon = nieuwe persoon ("Baeldung", 25); assertThat (person, hasProperty ("naam")); }

We kunnen ook kijken of Persoon heeft de adres property, geïnitialiseerd in New York:

@Test openbare ongeldig gegevenBean_whenHasCorrectValue_thenCorrect () {Persoon persoon = nieuwe persoon ("Baeldung", "New York"); assertThat (person, hasProperty ("adres", equalTo ("New York"))); }

We kunnen net zo goed kijken of er twee zijn Persoon objecten zijn geconstrueerd met dezelfde waarden:

@Test openbare ongeldig gegeven2Beans_whenHavingSameValues_thenCorrect () {Persoon person1 = nieuwe persoon ("Baeldung", "New York"); Persoon person2 = nieuwe persoon ("Baeldung", "New York"); assertThat (person1, samePropertyValuesAs (person2)); } 

6. Het Verzameling Matcher

Hamcrest biedt matchers voor inspectie Verzamelings.

Eenvoudige controle om erachter te komen of een Verzameling is leeg:

@Test openbare leegte gegevenCollection_whenEmpty_thenCorrect () {Lijst emptyList = nieuwe ArrayList (); assertThat (emptyList, empty ()); }

Om de grootte van een Verzameling:

@Test openbare ongeldig gegevenAList_whenChecksSize_thenCorrect () {Lijst hamcrestMatchers = Arrays.asList ("collecties", "bonen", "tekst", "nummer"); assertThat (hamcrestMatchers, hasSize (4)); }

We kunnen het ook gebruiken om te beweren dat een array een vereiste grootte heeft:

@Test openbare ongeldig gegevenArray_whenChecksSize_thenCorrect () {String [] hamcrestMatchers = {"Collections", "Beans", "text", "number"}; assertThat (hamcrestMatchers, arrayWithSize (4)); }

Om te controleren of a Verzameling bevat gegeven leden, ongeacht de volgorde:

@Test openbare ongeldig gegevenAListAndValues_whenChecksListForGivenValues_thenCorrect () {List hamcrestMatchers = Arrays.asList ("Collections", "Beans", "text", "number"); assertThat (hamcrestMatchers, containsInAnyOrder ("bonen", "tekst", "collecties", "nummer")); }

Om verder te beweren dat de Verzameling leden zijn in de opgegeven volgorde:

@Test openbare ongeldig gegevenAListAndValues_whenChecksListForGivenValuesWithOrder_thenCorrect () {List hamcrestMatchers = Arrays.asList ("Collections", "Beans", "text", "number"); assertThat (hamcrestMatchers, bevat ("collecties", "bonen", "tekst", "nummer")); }

Om te controleren of een array een enkel gegeven element heeft:

@Test openbare ongeldig gegevenArrayAndValue_whenValueFoundInArray_thenCorrect () {String [] hamcrestMatchers = {"Collections", "Beans", "text", "number"}; assertThat (hamcrestMatchers, hasItemInArray ("tekst")); }

We kunnen ook een alternatieve matcher gebruiken voor dezelfde test:

@Test openbare ongeldig gegevenValueAndArray_whenValueIsOneOfArrayElements_thenCorrect () {String [] hamcrestMatchers = {"Collections", "Beans", "text", "number"}; assertThat ("text", isOneOf (hamcrestMatchers)); }

Of toch kunnen we hetzelfde doen met een andere matcher zoals:

@Test openbare ongeldig gegevenValueAndArray_whenValueFoundInArray_thenCorrect () {String [] array = nieuwe String [] {"Collections", "Beans", "text", "number"}; assertThat ("bonen", isIn (array)); }

We kunnen ook controleren of de array gegeven elementen bevat, ongeacht de volgorde:

@Test openbare ongeldig gegevenArrayAndValues_whenValuesFoundInArray_thenCorrect () {String [] hamcrestMatchers = {"Collections", "Beans", "text", "number"}; assertThat (hamcrestMatchers, arrayContainingInAnyOrder ("bonen", "collecties", "nummer", "tekst")); }

Om te controleren of de array bepaalde elementen bevat, maar in de opgegeven volgorde:

@Test openbare ongeldig gegevenArrayAndValues_whenValuesFoundInArrayInOrder_thenCorrect () {String [] hamcrestMatchers = {"Collections", "Beans", "text", "number"}; assertThat (hamcrestMatchers, arrayContaining ("Collections", "Beans", "text", "number")); }

Toen onze Verzameling is een Kaart, we kunnen de volgende matchers gebruiken in deze respectieve functies:

Om te controleren of het een bepaalde sleutel bevat:

@Test openbare leegte gegevenMapAndKey_whenKeyFoundInMap_thenCorrect () {Map map = new HashMap (); map.put ("blognaam", "baeldung"); assertThat (map, hasKey ("blognaam")); }

en een bepaalde waarde:

@Test openbare leegte gegevenMapAndValue_whenValueFoundInMap_thenCorrect () {Map map = new HashMap (); map.put ("blognaam", "baeldung"); assertThat (map, hasValue ("baeldung")); }

en tenslotte een gegeven item (sleutel, waarde):

@Test openbare ongeldige gegevenMapAndEntry_whenEntryFoundInMap_thenCorrect () {Map map = new HashMap (); map.put ("blognaam", "baeldung"); assertThat (map, hasEntry ("blognaam", "baeldung")); }

7. Het Aantal Matcher

De Aantal matchers worden gebruikt om beweringen uit te voeren op variabelen van de Aantal klasse.

Controleren groter dan staat:

@Test openbare ongeldig gegevenAnInteger_whenGreaterThan0_thenCorrect () {assertThat (1, groterThan (0)); }

Controleren groter dan of gelijk aan staat:

@Test openbare leegte gegevenAnInteger_whenGreaterThanOrEqTo5_thenCorrect () {assertThat (5, grotereThanOrEqualTo (5)); }

Controleren minder dan staat:

@Test openbare ongeldig gegevenAnInteger_whenLessThan0_thenCorrect () {assertThat (-1, lessThan (0)); }

Controleren minder dan of gelijk aan staat:

@Test openbare ongeldig gegevenAnInteger_whenLessThanOrEqTo5_thenCorrect () {assertThat (-1, lessThanOrEqualTo (5)); }

Controleren dichtbij staat:

@Test openbare leegte gegevenADouble_whenCloseTo_thenCorrect () {assertThat (1.2, closeTo (1, 0.5)); }

Laten we goed op de laatste matcher letten, dichtbij. Het eerste argument, de operand, is het argument waarmee het doel wordt vergeleken en het tweede argument is de toegestane afwijking van de operand . Dit betekent dat als het doel operand + deviatie of operand-deviatie is, de test zal slagen.

8. De tekst Matcher

Bewering op Draads is eenvoudiger, netter en intuïtiever gemaakt met Hamcrest‘S tekstmatchers. We gaan ze in deze sectie bekijken.

Om te controleren of a Draad is leeg:

@Test openbare ongeldig gegevenString_whenEmpty_thenCorrect () {String str = ""; assertThat (str, isEmptyString ()); }

Om te controleren of a Draad is leeg of nul:

@Test openbare leegte gegevenString_whenEmptyOrNull_thenCorrect () {String str = null; assertThat (str, isEmptyOrNullString ()); }

Om te controleren op gelijkheid van twee Draads terwijl de witruimte wordt genegeerd:

@Test openbare ongeldig gegeven2Strings_whenEqualRegardlessWhiteSpace_thenCorrect () {String str1 = "text"; String str2 = "tekst"; assertThat (str1, equalToIgnoringWhiteSpace (str2)); }

We kunnen ook controleren op de aanwezigheid van een of meer subtekenreeksen in een gegeven Draad in een bepaalde volgorde:

@Test openbare leegte gegevenString_whenContainsGivenSubstring_thenCorrect () {String str = "calligraphy"; assertThat (str, stringContainsInOrder (Arrays.asList ("call", "graph"))); }

Ten slotte kunnen we de gelijkheid van twee controleren Draads ongeacht het geval:

@Test openbare ongeldig gegeven2Strings_whenEqual_thenCorrect () {String a = "foo"; String b = "FOO"; assertThat (a, equalToIgnoringCase (b)); }

9. De Core API

De Hamcrest core API moet worden gebruikt door externe framework-providers. Het biedt ons echter een aantal geweldige constructies om onze unit-tests leesbaarder te maken en ook enkele kern-matchers die net zo gemakkelijk kunnen worden gebruikt.

Leesbaarheid met de is construeren op een matcher:

@Test openbare ongeldig gegeven2Strings_whenIsEqualRegardlessWhiteSpace_thenCorrect () {String str1 = "text"; String str2 = "tekst"; assertThat (str1, is (equalToIgnoringWhiteSpace (str2))); }

De is construeren op een eenvoudig datatype:

@Test openbare ongeldig gegeven2Strings_whenIsEqual_thenCorrect () {String str1 = "text"; String str2 = "tekst"; assertThat (str1, is (str2)); }

Ontkenning met de niet construeren op een matcher:

@Test openbare ongeldig gegeven2Strings_whenIsNotEqualRegardlessWhiteSpace_thenCorrect () {String str1 = "text"; String str2 = "teksten"; assertThat (str1, niet (equalToIgnoringWhiteSpace (str2))); }

De niet construeren op een eenvoudig datatype:

@Test openbare ongeldig gegeven2Strings_whenNotEqual_thenCorrect () {String str1 = "text"; String str2 = "teksten"; assertThat (str1, niet (str2)); }

Controleer of a Draad bevat een gegeven subtekenreeks:

@Test openbare ongeldig gegevenAStrings_whenContainsAnotherGivenString_thenCorrect () {String str1 = "kalligrafie"; String str2 = "call"; assertThat (str1, bevatString (str2)); }

Controleer of a Draad begint met een gegeven sub-string:

@Test openbare ongeldig gegevenAString_whenStartsWithAnotherGivenString_thenCorrect () {String str1 = "kalligrafie"; String str2 = "call"; assertThat (str1, startsWith (str2)); }

Controleer of a Draad eindigt met de opgegeven subtekenreeks:

@Test openbare ongeldig gegevenAString_whenEndsWithAnotherGivenString_thenCorrect () {String str1 = "kalligrafie"; String str2 = "phy"; assertThat (str1, endsWith (str2)); }

Controleer of er twee zijn Voorwerps zijn van dezelfde instantie:

@Test openbare ongeldig gegeven2Objects_whenSameInstance_thenCorrect () {Cat cat = nieuwe Cat (); assertThat (cat, sameInstance (cat)); }

Controleer of een Voorwerp is een instantie van een bepaalde klasse:

@Test openbare leegte gegevenAnObject_whenInstanceOfGivenClass_thenCorrect () {Cat cat = nieuwe Cat (); assertThat (cat, instanceOf (Cat.class)); }

Controleer of alle leden van een Verzameling voldoen aan een voorwaarde:

@Test openbare ongeldig gegevenList_whenEachElementGreaterThan0_thenCorrect () {Lijstlijst = Arrays.asList (1, 2, 3); int baseCase = 0; assertThat (lijst, elk item (groter dan (baseCase))); }

Controleer of a Draad is niet nul:

@Test openbare ongeldig gegevenString_whenNotNull_thenCorrect () {String str = "notnull"; assertThat (str, notNullValue ()); }

Keten voorwaarden samen, test slaagt wanneer het doel aan een van de voorwaarden voldoet, vergelijkbaar met logische OF:

@Test openbare ongeldig gegevenString_whenMeetsAnyOfGivenConditions_thenCorrect () {String str = "calligraphy"; String start = "call"; String end = "foo"; assertThat (str, anyOf (startsWith (start), containsString (end))); }

Keten voorwaarden samen, test slaagt alleen als het doel aan alle voorwaarden voldoet, vergelijkbaar met logische EN:

@Test openbare ongeldig gegevenString_whenMeetsAllOfGivenConditions_thenCorrect () {String str = "calligraphy"; String start = "call"; String end = "phy"; assertThat (str, allOf (startsWith (start), endsWith (end))); }

10. Een aangepaste matcher

We kunnen onze eigen matcher definiëren door uit te breiden Typ SafeMatcher. In deze sectie zullen we een aangepaste matcher maken waarmee een test alleen kan slagen als het doel een positief geheel getal is.

openbare klasse IsPositiveInteger breidt TypeSafeMatcher uit {public void descriptionTo (Beschrijving beschrijving) {description.appendText ("een positief geheel getal"); } @Factory openbare statische Matcher isAPositiveInteger () {retourneer nieuwe IsPositiveInteger (); } @Override beschermde booleaanse matchesSafely (Integer integer) {return integer> 0; }}

We hoeven alleen het matchSafely methode die controleert of het doel inderdaad een positief geheel getal is en de beschrijven naar methode die een foutmelding geeft voor het geval de test niet slaagt.

Hier is een test die onze nieuwe aangepaste matcher gebruikt:

@ Test openbare ongeldig gegevenInteger_whenAPositiveValue_thenCorrect () {int num = 1; assertThat (num, isAPositiveInteger ()); }

en hier is een foutbericht dat we krijgen sinds we een niet-positief geheel getal zijn gepasseerd:

java.lang.AssertionError: Verwacht: een positief geheel getal maar: was 

11. Conclusie

In deze tutorial hebben we verkende de Hamcrest API en leerden hoe we er betere en beter onderhoudbare unit tests mee kunnen schrijven.

De volledige implementatie van al deze voorbeelden en codefragmenten is te vinden in mijn Hamcrest github-project.