Programmering

Hamcrest indeholdende matchere

Hamcrest 1.3 Javadoc-dokumentationen til Matchers-klassen tilføjer mere dokumentation for flere af denne klasses metoder, end der var tilgængelig i Hamcrest 1.2. For eksempel har de fire overbelastede metoder metoder med mere beskrivende Javadoc-dokumentation som vist i de to sammenligningsskærmbillede, der vises nedenfor.

Selvom man kan finde ud af, hvordan "indeholder" matchere bare ved at prøve dem, gør Javadoc i Hamcrest 1.3 det lettere at læse, hvordan de fungerer. De fleste Java-udviklere tænker sandsynligvis på adfærd som String.contains (CharSequence) eller Collection.contains (Object), når de tænker på en indeholder() metode. Med andre ord tænker de fleste Java-udviklere sandsynligvis på "indeholder" som en beskrivelse af, om String / Collection indeholder de medfølgende tegn / objekter blandt andre mulige tegn / objekter. For Hamcrest-matchere har "indeholder" imidlertid en meget mere specifik betydning. Da Hamcrest 1.3-dokumentationen gør det meget tydeligere, er "indeholder" matchere meget mere følsomme over for antallet af varer og rækkefølgen af ​​varer, der sendes til disse metoder.

Mine eksempler vist her bruger JUnit og Hamcrest. Det er vigtigt at understrege her, at Hamcrests JAR-fil skal vises på enhedstestens klassebane før JUnits JAR-fil, ellers skal jeg bruge den "specielle" JUnit JAR-fil, der er bygget til brug sammen med den uafhængige Hamcrest JAR. Brug af en af ​​disse tilgange undgår NoSuchMethodError og andre fejl (som org.hamcrest.Matcher.describeMismatch fejl), der skyldes uoverensstemmende versioner af klasser. Jeg har skrevet om denne JUnit / Hamcrest-nuance i blogindlægget Moving Beyond Core Hamcrest i JUnit.

De næste to skærmbilleder viser skærmbilledet (som vist i NetBeans 7.3) for enhedstestkodestykker, som jeg viser senere i bloggen for at demonstrere Hamcrest-holdige matchere. Testene formodes at have nogle fiaskoer (7 test bestået og 4 test fejler) for at gøre det indlysende, hvor Hamcrest-matchere muligvis ikke fungerer, som man forventer uden at læse Javadoc. Det første billede viser kun 5 tests, der er bestået, 2 tests mislykkedes og 4 tests, der forårsager fejl. Dette skyldes, at jeg har JUnit opført før Hamcrest på NetBeans-projektets "Test Libraries" klassesti. Det andet billede viser de forventede resultater, fordi Hamcrest JAR opstår før JUnit JAR i projektets "Test Libaries" klassesti.

Med henblik på denne demonstration har jeg en simpel konstrueret klasse, der skal testes. Kildekoden til det Vigtigste klasse vises derefter.

Main.java

pakke dustin. eksempler; import java.util.Collections; importere java.util.HashSet; importere java.util.Set; / ** * Hovedklasse, der skal testes enhed. * * @forfatter Dustin * / public class Main {/ ** Bruger Java 7s diamantoperatør. * / private sæt strenge = nye HashSet (); public Main () {} public boolean addString (final String newString) {returner this.strings.add (newString); } public Set getStrings () {return Collections.unmodifiableSet (this.strings); }} 

Med den klasse, der skal testes, er det nu tid til at se på at opbygge nogle JUnit-baserede tests med Hamcrest-matchere. Specifikt skal testene sikre, at strenge tilføjes via klassens addString (streng) metoden er i dens underliggende Sæt og tilgængelig via getStrings () metode. Enhedstestmetoderne, der vises nedenfor, demonstrerer, hvordan man bruger Hamcrest-matchere korrekt til at afgøre, om tilføjede strenge er indeholdt i klassens underliggende Sæt

Brug af Hamcrest indeholder () Matcher med enkelt streng i sætværker

 / ** * Denne test vil bestå, fordi der kun er en enkelt streng, og så den vil * indeholde, at den enkelte streng og rækkefølge vil være korrekt underforstået. * / @Test public void testAddStringAndGetStringsWithContainsForSingleStringSoWorks () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); sidste sæt strenge = subject.getStrings (); assertThat (strings, indeholder ("Java")); } 

Enhedstesten vist ovenfor består, fordi Sæt har kun en streng i den, og rækkefølgen og antallet af strenge testet med indeholder matcher matches.

Brug af Hamcrest Indeholder det samme antal elementer, hvis ordren matcher

 / ** * Matcheren "indeholder" forventer nøjagtig rækkefølge, hvilket virkelig betyder, at den * ikke skal bruges i forbindelse med {@code Set} s. Enten fungerer denne metode *, og metoden med samme navn og "2" i slutningen fungerer ikke eller * omvendt. * / @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks1 () {final Hovedemne = nyt Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, indeholder ("Java", "Groovy")); } / ** * Matcheren "indeholder" forventer nøjagtig rækkefølge, hvilket virkelig betyder, at den ikke * skal bruges i forbindelse med {@code Set}. Enten fungerer denne metode * typisk, og metoden med samme navn og "1" fungerer ikke eller * omvendt. * / @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks2 () {final Hovedemne = nyt Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, indeholder ("Groovy", "Java")); } 

De to eksempler på enhedstest, der er vist ovenfor, og deres resulterende output af at køre disse test som vist i det forrige skærmbillede, viser, at så længe antallet af argumenter til indeholder() matcher er det samme som antallet af strenge i samlingen, der testes, kampen kan arbejde hvis de testede elementer er i nøjagtig samme rækkefølge som elementerne i samlingen. Med en uordnet Sæt, denne ordre kan ikke påberåbes, så indeholder() sandsynligvis ikke vil være en god matcher at bruge med en enhedstest på en Sæt af mere end et element.

Brug af Hamcrest Indeholder med forskellige antal elementer fungerer aldrig

 / ** * Demonstration, der indeholder, passerer IKKE, når der er et andet antal * elementer, der bliver spurgt om, indeholder end i samlingen. * / @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements1 () {final Hovedemne = nyt Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, indeholder ("Java")); } / ** * Demonstration, der indeholder, passerer IKKE, når der er et andet antal * elementer, der er spurgt om, indeholder end i samlingen, selv når de er i * anden rækkefølge. * / @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements2 () {final Hovedemne = nyt Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, indeholder ("Groovy")); } 

Som JUnit-testresultaterne indikerer, passerer disse to enhedstest aldrig, fordi antallet af elementer, der testes for i Sæt er færre end antallet af elementer i Sæt. Med andre ord, dette beviser, at indeholder() matcher tester ikke kun for, at et givet element er i en samling: det tester for, at alle angivne elementer er til stede og i den angivne rækkefølge. Dette kan være for begrænsende i nogle tilfælde, så nu går jeg videre til nogle andre kampe, Hamcrest giver for at afgøre, om et element er indeholdt i en bestemt samling.

Brug af Hamcrest's indeholderInAnyOrder () Matcher

Det indeholderInAnyOrder matcher er ikke så streng som indeholder() matcher: det gør det muligt for testede elementer at være i en hvilken som helst rækkefølge inden for den indeholdende samling for at passere.

 / ** * Test af addString og getStrings-metoder i klasse Main ved hjælp af Hamcrest * matcher indeholderInAnyOrder. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrder () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatCSharp = subject.addString ("C #"); endelige boolske resultatGroovy = subject.addString ("Groovy"); endelige boolske resultatScala = subject.addString ("Scala"); endelige boolske resultatClojure = subject.addString ("Clojure"); sidste sæt strenge = subject.getStrings (); assertThat (strings, containInAnyOrder ("Java", "C #", "Groovy", "Scala", "Clojure")); } / ** * Brug containInAnyOrder og vis, at ordren ikke betyder noget, så længe * alle angivne poster er i samlingen i en eller anden rækkefølge. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrderAgain () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, containInAnyOrder ("Java", "Groovy")); assertThat (strings, containInAnyOrder ("Groovy", "Java")); } 

De to enhedstest, der er vist umiddelbart over begge, passerer på trods af, at strengene, der testes, leveres til indeholderInAnyOrder () matcher i en anden rækkefølge end hvad de kunne eksistere i for begge samlinger. Dog mindre streng indeholderInAnyOrder () matcher kræver stadig, at alle elementer i den indeholdende samling skal specificeres for at blive bestået. Den følgende enhedstest består ikke, fordi denne betingelse ikke er opfyldt.

 / ** * Dette mislykkes, fordi containInAnyOrder kræver, at alle varer matches *, selvom de er i anden rækkefølge. Da kun et element er prøvet og to * elementer i samlingen, vil det stadig mislykkes. Med andre ord betyder ordre * ikke noget med indeholderInAnyOrder, men alle elementer i samlingen * skal stadig sendes til matchesInAnyOrder-matcheren, bare ikke i * nøjagtig samme rækkefølge. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrderDiffNumberElements () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, containInAnyOrder ("Java")); } 

Hamcrest hasItem () og hasItems () Matchers fungerer som lyde

Som vist i de næste to enheds testmetoder (som begge består), Hamcrest hasItem () (for en enkelt vare) og hasItems (for flere varer) tester med succes, om en samling har henholdsvis en eller flere end en specificeret vare uden hensyntagen til ordre eller antal af specificerede varer. Dette fungerer virkelig mere som de fleste Java-udviklere er vant til at "indeholder", når de arbejder med strenge og samlinger.

 / ** * Demonstrate hasItem () fungerer også til bestemmelse af, at en samling indeholder * et bestemt element. * / @Test public void testAddStringAndGetStringsWithHasItem () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, hasItem ("Groovy")); assertThat (strings, hasItem ("Java")); } / ** * Demonstrer, der hasItems fungerer til at bestemme, at en samling har en * eller flere genstande, og at antallet af varer og rækkefølgen af ​​varerne * ikke er signifikant ved bestemmelse af pass / fiasko. * / @Test public void testAddStringAndGetStringsWithHasItems () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat (strings, hasItems ("Groovy", "Java")); assertThat (strings, hasItems ("Java", "Groovy")); assertThat (strings, hasItems ("Groovy")); assertThat (strings, hasItems ("Java")); } 

Hamcrest isIn () Matcher tester indeslutning fra anden retning

Den netop diskuterede hasItem () og hasItems () matchere er mindre strenge end indeholder() og endnu mindre streng end indeholderInAnyOrder () og er ofte, hvad man ønsker, når man blot ønsker at sikre, at en eller flere genstande er et eller andet sted i en samling uden bekymring for varens rækkefølge i den samling, eller at andre mulige genstande er i denne samling. En anden måde at bruge Hamcrest til at bestemme det samme forhold, men fra det modsatte perspektiv, er at bruge er i matcher. Det er i matcher bestemmer, om en vare er et sted med samlingen, der leveres til matcheren, uden hensyntagen til den vares ordre i samlingen, eller om der er andre varer i den, der indeholder samlingen.

 / ** * Brug isIn matcher til at teste individuelt element er i den medfølgende samling. * / @Test public void testAddStringAndGetStringsWithIsIn () {final Main subject = new Main (); endelige boolske resultatJava = subject.addString ("Java"); endelige boolske resultatGroovy = subject.addString ("Groovy"); sidste sæt strenge = subject.getStrings (); assertThat ("Groovy", isIn (strings)); assertThat ("Java", isIn (strings)); }