Ohjelmointi

Hamcrest, joka sisältää ottelijoita

Matchers-luokan Hamcrest 1.3 Javadoc -dokumentaatio lisää enemmän dokumentaatiota useille kyseisen luokan menetelmistä kuin mitä oli saatavana Hamcrest 1.2: ssa. Esimerkiksi neljällä ylikuormitetulla menetelmällä on kuvailevampi Javadoc-dokumentaatio, kuten seuraavissa kahdessa vertailunäytön tilannekuvassa näkyy.

Vaikka voidaan selvittää, kuinka "sisältää" ottelijat toimivat vain kokeilemalla niitä, Javadoc in Hamcrest 1.3 helpottaa niiden toiminnan lukemista. Useimmat Java-kehittäjät luultavasti ajattelevat käyttäytymistä kuten String.contains (CharSequence) tai Collection.contains (Object), kun he ajattelevat sisältää() menetelmä. Toisin sanoen useimmat Java-kehittäjät luultavasti ajattelevat "sisältää" kuvaavan, sisältääkö merkkijono / kokoelma annettuja merkkejä / objekteja muiden mahdollisten merkkien / objektien kanssa. Hamcrestin ottelijoille "sisältää" on kuitenkin paljon tarkempi merkitys. Koska Hamcrest 1.3 -dokumentaatio tekee paljon selvemmäksi, "sisältää" -sovellukset ovat paljon herkempiä kohteiden määrälle ja kohteiden järjestykselle, joka siirretään näihin menetelmiin.

Tässä esitetyissä esimerkeissäni käytetään JUnitia ja Hamcrestiä. On tärkeää korostaa tässä, että Hamcrestin JAR-tiedoston on oltava yksikötestien luokkaradalla ennen JUnitin JAR-tiedostoa, tai muuten minun on käytettävä "erityistä" JUnit JAR -tiedostoa, joka on rakennettu käytettäväksi erillisen Hamcrest JAR: n kanssa. Kummallakin näistä lähestymistavoista vältetään NoSuchMethodError ja muut virheet (kuten org.hamcrest.Matcher.describeMismatch -virhe), jotka johtuvat luokkien virheellisistä versioista. Olen kirjoittanut tästä JUnit / Hamcrest -vivahteesta blogiviestissä Moving Beyond Core Hamcrest JUnitissa.

Seuraavat kaksi näytön tilannekuvaa osoittavat tulokset (kuten on esitetty NetBeans 7.3: ssä) yksikkötestikoodinpätkistä, jotka näytän myöhemmin blogissa osoittamaan Hamcrestin sisältäviä ottelijoita. Testeissä oletetaan olevan joitain epäonnistumisia (7 kokeen läpäisyä ja 4 epäonnistunutta testiä), jotta voidaan tehdä selväksi, missä Hamcrestin ottelijat eivät välttämättä toimi odotetusti lukematta Javadocia. Ensimmäisessä kuvassa näkyy vain 5 läpäisevää testiä, 2 epäonnistunutta testiä ja 4 virheitä aiheuttavaa testiä. Tämä johtuu siitä, että minulla on JUnit lueteltu ennen Hamcrestiä NetBeans-projektin "Test Libraries" -luokan polulla. Toinen kuva näyttää odotetut tulokset, koska Hamcrest JAR esiintyy ennen JUnit JARia projektin "Test Libaries" -luokan polulla.

Tätä esittelyä varten minulla on yksinkertainen keksitty luokka, joka testataan. Lähdekoodi siihen Main luokka näkyy seuraavaksi.

Main.java

pakkaus pölyä.esimerkkejä; tuo java.util.Collections; tuo java.util.HashSet; tuo java.util.Set; / ** * Yksikkö testattava pääluokka. * * @author Dustin * / public class Main {/ ** Käyttää Java 7: n timanttioperaattoria. * / private Set -merkkijonot = uusi HashSet (); public Main () {} public boolean addString (final String newString) {return this.strings.add (newString); } public set getStrings () {return Collections.unmodifiableSet (this.merkkijonot); }} 

Kun testattava luokka on esitetty, on nyt aika tarkastella JUnit-pohjaisten testien rakentamista Hamcrestin ottelijoiden kanssa. Testien on erityisesti varmistettava, että merkkijonot lisätään luokan kautta addString (merkkijono) menetelmän taustalla Aseta ja sinne pääsee getStrings () menetelmä. Seuraavaksi esitetyt yksikkötestimenetelmät osoittavat, kuinka Hamcrest-sovittimia voidaan käyttää asianmukaisesti sen määrittämiseksi, sisältävätkö lisätyt merkkijonot luokan taustalla Aseta

Hamcrestin käyttäminen sisältää () Matcher with Single String in Set Works

 / ** * Tämä testi läpäisee, koska siinä on vain yksi merkkijono, joten se * sisältää kyseisen merkkijonon ja järjestys on implisiittisesti oikea. * / @Test public void testAddStringAndGetStringsWithContainsForSingleStringSoWorks () {final Pääaihe = uusi Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältää ("Java")); } 

Yllä esitetty yksikkötesti läpäisee, koska Aseta vain yksi merkkijono siinä, joten niiden kanssa testattujen merkkijonojen järjestys ja määrä sisältää ottelupelit.

Hamcrestin käyttö sisältää saman määrän elementtejä, jos tilaukset vastaavat

 / ** * "Sisältää" -hakija odottaa tarkkaa järjestystä, mikä tarkoittaa sitä, että sitä ei tulisi * käyttää yhdessä {@code Set} -merkkien kanssa. Tyypillisesti joko tämä menetelmä * toimii ja menetelmä, jolla on sama nimi ja "2" lopussa, ei toimi tai * päinvastoin. * / @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks1 () {final Main subject = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältää ("Java", "Groovy")); } / ** * "Sisältää" -hakija odottaa tarkkaa järjestystä, mikä tarkoittaa sitä, että sitä ei tule * käyttää yhdessä {@code Set} -merkkien kanssa. Tyypillisesti joko tämä menetelmä * toimii ja menetelmä, jolla on sama nimi ja "1" lopussa, ei toimi tai * päinvastoin. * / @Test public void testAddStringAndGetStringsWithContainsForMultipleStringsNotWorks2 () {final Main subject = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältää ("Groovy", "Java")); } 

Kaksi yllä esitettyä esimerkkiyksikkötestiä ja niiden tuloksena saadun testin suorittaminen edellisen näytön tilannekuvan mukaan osoittavat, että niin kauan kuin argumenttien määrä sisältää() matcher ovat samat kuin testattavan kokoelman merkkijonojen, ottelun saattaa työ jos testatut elementit ovat täsmälleen samassa järjestyksessä kuin kokoelman elementit. Järjestämättömällä Aseta, tähän määräykseen ei voida vedota, joten sisältää() ei todennäköisesti ole hyvä ottelija käytettäväksi a-yksikön testin kanssa Aseta useammasta kuin yhdestä elementistä.

Eri elementtien lukumäärää sisältävän Hamcrestin käyttö ei koskaan toimi

 / ** * Osoita, että sisältö EI läpäise, kun sisältöistä kysytään eri määrä * elementtejä kuin kokoelmassa. * / @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements1 () {final Pääaihe = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältää ("Java")); } / ** * Osoita, että sisältö EI läpäise, kun sisältökysymyksistä kysytään eri määrä * elementtejä kuin kokoelmassa, vaikka * eri järjestyksessä. * / @Test public void testAddStringAndGetStringsWithContainsNotWorksDifferentNumberElements2 () {final Pääaihe = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältää ("Groovy")); } 

Kuten JUnit-testitulokset osoittavat, nämä kaksi yksikkötestiä eivät koskaan läpäise, koska testattavien elementtien lukumäärä Aseta on vähemmän kuin elementtien lukumäärä Aseta. Toisin sanoen tämä osoittaa, että sisältää() matcher ei testaa yksinkertaisesti sitä, onko tietty elementti kokoelmassa: se testaa kaikkien läsnä olevien määritettyjen elementtien ja määrätyssä järjestyksessä. Tämä saattaa olla joissakin tapauksissa liian rajoittava, joten nyt siirryn joihinkin muihin otteluihin, joita Hamcrest tarjoaa määrittelemään, onko elementti tietyssä kokoelmassa.

Käyttämällä Hamcrestin sisältämää sisältöäInAnyOrder () Matcher

sisältääInAnyOrder ottelija ei ole niin tiukka kuin sisältää() matcher: sen avulla testatut elementit voivat olla missä tahansa järjestyksessä sisältävän kokoelman sisällä.

 / ** * Luokan Main addString- ja getStrings-menetelmien testi käyttämällä Hamcrest * matcher -ohjelmaa sisältääInAnyOrder. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrder () {final Pääkohde = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosCSharp = subject.addString ("C #"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopullinen looginen tulosScala = subject.addString ("Scala"); lopullinen looginen tulosClojure = subject.addString ("Clojure"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältääInAnyOrder ("Java", "C #", "Groovy", "Scala", "Clojure")); } / ** * Käytä includeInAnyOrder ja näytä, että järjestyksellä ei ole väliä, kunhan * kaikki annetut merkinnät ovat kokoelmassa jossakin järjestyksessä. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrderAgain () {final Pääaihe = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältääInAnyOrder ("Java", "Groovy")); assertThat (merkkijonot, sisältääInAnyOrder ("Groovy", "Java")); } 

Molemmat heti näytetyt yksikötestit läpäisevät huolimatta siitä, että testattavat kielet toimitetaan sisältääInAnyOrder () matcher eri järjestyksessä kuin mitä he voisivat olla molemmissa kokoelmissa. Kuitenkin vähemmän tiukka sisältääInAnyOrder () matcher vaatii edelleen, että kaikki sisältävän kokoelman elementit on määritelty läpäisemään. Seuraava yksikkötesti ei läpäise, koska tämä ehto ei täyty.

 / ** * Tämä epäonnistuu, koska containsInAnyOrder vaatii kaikkien kohteiden vastaavuuden *, vaikka ne olisivat eri järjestyksessä. Kun vain yksi elementti on kokeiltu ja kaksi * elementtiä kokoelmassa, se epäonnistuu edelleen. Toisin sanoen, järjestyksellä * ei ole merkitystä, kun mukana onInAnyOrder, mutta kaikki kokoelman * elementit on silti välitettävä sisällytettävälle sisällönAnyOrder-sovittimelle, ei vain * samassa järjestyksessä. * / @Test public void testAddStringAndGetStringsWithContainsInAnyOrderDiffNumberElements () {final Pääaihe = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, sisältääInAnyOrder ("Java")); } 

Hamcrest hasItem () ja hasItems () Matchers toimivat kuten äänet

Kuten seuraavissa kahdessa yksikötestimenetelmässä (jotka molemmat läpäisevät), Hamcrest hasItem () (yhdelle tuotteelle) ja hasItems (useille tuotteille) testaa onnistuneesti, onko kokoelmassa yksi tai useampi määritetty kohde vastaavasti järjestyksen tai määritettyjen tuotteiden lukumäärän suhteen. Tämä toimii todellakin enemmän kuin useimmat Java-kehittäjät ovat tottuneet "sisältämään" työskentelyä Stringsin ja kokoelmien parissa.

 / ** * Osoita hasItem () toimii myös määritettäessä kokoelma sisältää * tietyn kohteen. * / @Test public void testAddStringAndGetStringsWithHasItem () {final Pääaihe = uusi Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, hasItem ("Groovy")); assertThat (merkkijonot, hasItem ("Java")); } / ** * Osoita, että hasItems toimii sen määrittämiseksi, että kokoelmassa on yksi tai useampia kohteita ja että kohteiden lukumäärällä ja kohteiden järjestyksellä * ei ole merkitystä määritettäessä läpäisyä / epäonnistumista. * / @Test public void testAddStringAndGetStringsWithHasItems () {final Pääkohde = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat (merkkijonot, hasItems ("Groovy", "Java")); assertThat (merkkijonot, hasItems ("Java", "Groovy")); assertThat (merkkijonot, hasItems ("Groovy")); assertThat (merkkijonot, hasItems ("Java")); } 

Hamcrest on () Matcher testaa rajoituksia muusta suunnasta

Juuri keskusteltu hasItem () ja hasItems () ottelijat ovat vähemmän tiukkoja kuin sisältää() ja jopa vähemmän tiukka kuin sisältääInAnyOrder () ja ovat usein mitä haluamme, kun halutaan yksinkertaisesti varmistaa, että yksi tai useampi esine on jonnekin kokoelmassa huolimatta tuotteen järjestyksestä kyseisessä kokoelmassa tai siitä, että muut mahdolliset tuotteet ovat kyseisessä kokoelmassa. Yksi toinen tapa käyttää Hamcrestiä saman suhteen määrittämiseen, mutta päinvastaisesta näkökulmasta, on käyttää isIn ottelija. isIn matcher määrittää, onko esine jossain ottelijalle toimitetussa kokoelmassa ottamatta huomioon kyseisen tuotteen järjestystä kokoelmassa vai onko muita esineitä siinä, joka sisältää kokoelman.

 / ** * Käytä isIn matcheria testataksesi yksittäisen elementin mukana toimitetussa kokoelmassa. * / @Test public void testAddStringAndGetStringsWithIsIn () {final Main subject = new Main (); lopullinen looginen tulosJava = subject.addString ("Java"); lopullinen looginen tulosGroovy = subject.addString ("Groovy"); lopulliset merkkijonot = subject.getStrings (); assertThat ("Groovy", isIn (merkkijonot)); assertThat ("Java", isIn (merkkijonot)); } 
$config[zx-auto] not found$config[zx-overlay] not found