Ohjelmointi

JUnit 5 -opetusohjelma, osa 1: Yksikkötestaus JUnit 5: n, Mockiton ja Hamcrestin kanssa

JUnit 5 on uusi de facto -standardi Java-yksikötestien kehittämiseksi. Tämä uusin versio on jättänyt jälkeensä Java 5: n rajoitteet ja integroinut monia Java 8: n ominaisuuksia, erityisesti lambda-lausekkeiden tuen.

Tässä JUnit 5: n kaksiosaisen johdannon ensimmäisessä puoliskossa aloitat testaamisen JUnit 5: llä. Näytän sinulle, kuinka Maven-projekti määritetään käyttämään JUnit 5: tä, kuinka testejä kirjoitetaan @Testata ja @ParameterizedTest merkinnät ja miten työskennellä uusien elinkaarimerkintöjen kanssa JUnit 5: ssä. Näet myös lyhyen esimerkin suodatintunnisteiden käytöstä, ja näytän sinulle, kuinka JUnit 5 voidaan integroida kolmannen osapuolen väitteiden kirjastoon - tässä tapauksessa , Hamcrest. Lopuksi saat nopean, opastavan johdannon JUnit 5: n integroimisesta Mockitoon, jotta voit kirjoittaa vankempia yksikötestejä monimutkaisille, reaalimaailman järjestelmille.

lataa Hanki koodi Hanki lähdekoodi esimerkkejä tästä opetusohjelmasta. Luonut Steven Haines JavaWorldille.

Testiohjattu kehitys

Jos olet kehittänyt Java-koodia jonkin aikaa, olet todennäköisesti hyvin perehtynyt testiohjattuun kehitykseen, joten pidän tämän osan lyhyesti. On tärkeää ymmärtää miksi kirjoitamme kuitenkin yksikkötestejä sekä strategioita, joita kehittäjät käyttävät suunnitellessaan yksikötestejä.

Testiohjattu kehitys (TDD) on ohjelmistokehitysprosessi, joka yhdistää koodauksen, testauksen ja suunnittelun. Se on testin ensimmäinen lähestymistapa, jonka tarkoituksena on parantaa sovellusten laatua. Testiohjattu kehitys määritellään seuraavalla elinkaarella:

  1. Lisää testi.
  2. Suorita kaikki testisi ja tarkkaile uuden testin epäonnistumista.
  3. Ota koodi käyttöön.
  4. Suorita kaikki testisi ja seuraa uutta testiä.
  5. Refactor koodi.

Kuva 1 esittää tämän TDD-elinkaaren.

Steven Haines

Testien kirjoittamiseen ennen koodin kirjoittamista on kaksi tarkoitusta. Ensinnäkin se pakottaa sinut ajattelemaan yritysongelmaa, jonka yrität ratkaista. Esimerkiksi kuinka onnistuneiden skenaarioiden tulisi toimia? Mitkä olosuhteet epäonnistuvat? Kuinka heidän pitäisi epäonnistua? Toiseksi testaus antaa sinulle enemmän luottamusta testeihisi. Aina kun kirjoitan testejä koodin kirjoittamisen jälkeen, minun täytyy aina rikkoa ne varmistaakseni, että he todella havaitsevat virheitä. Testien kirjoittaminen välttää ensin tämän ylimääräisen vaiheen.

Testien kirjoittaminen onnelliselle polulle on yleensä helppoa: Hyvästä panoksesta luokan tulisi palauttaa deterministinen vastaus. Mutta negatiivisten (tai epäonnistuneiden) testitapausten kirjoittaminen, etenkin monimutkaisille komponenteille, voi olla monimutkaisempaa.

Harkitse esimerkkinä testien kirjoittamista tietokannan arkistoon. Hyvällä polulla lisätään tietue tietokantaan ja vastaanotetaan luotu objekti takaisin, mukaan lukien kaikki generoidut avaimet. Todellisuudessa meidän on myös harkittava ristiriidan mahdollisuutta, kuten lisätä tietue, jolla on ainutlaatuinen sarake-arvo, joka on jo toisen tietueen hallussa. Lisäksi, mitä tapahtuu, kun arkisto ei pysty muodostamaan yhteyttä tietokantaan, ehkä siksi, että käyttäjänimi tai salasana on muuttunut? Mitä tapahtuu, jos kuljetuksessa on verkkovirhe? Mitä tapahtuu, jos pyyntöä ei suoriteta määritetyssä aikakatkaisussa?

Vankan komponentin rakentamiseksi sinun on otettava huomioon kaikki todennäköiset ja epätodennäköiset skenaariot, kehitettävä niitä varten testit ja kirjoitettava koodisi näiden testien täyttämiseksi. Myöhemmin artikkelissa tarkastelemme strategioita erilaisten vikatilanteiden luomiseksi sekä joitain JUnit 5: n uusia ominaisuuksia, joiden avulla voit testata näitä skenaarioita.

Hyväksytään JUnit 5

Jos olet käyttänyt JUnitia jonkin aikaa, osa JUnit 5: n muutoksista on oikaisu. Tässä on korkean tason yhteenveto kahden version eroista:

  • JUnit 5 on nyt pakattu org.junit.jupiter ryhmä, joka muuttaa tapaa, jolla sisällytät sen Maven- ja Gradle-projektiisi.
  • JUnit 4 vaati vähintään JDK 5: n JDK: n; JUnit 5 vaatii vähintään JDK 8: n.
  • JUnit 4: t @Ennen, @Ennen tuntia, @Jälkeenja @Oppitunnin jälkeen merkinnät on korvattu seuraavilla: @BeforeEach, @BeforeAll, @AfterEachja @Kuitenkinvastaavasti.
  • JUnit 4: t @Jättää huomiotta huomautus on korvattu @Liikuntarajoitteinen merkintä.
  • @Kategoria huomautus on korvattu @Tag merkintä.
  • JUnit 5 lisää uuden väitemenetelmien sarjan.
  • Runners on korvattu laajennuksilla, uudella API: lla laajennusten toteuttajille.
  • JUnit 5 esittelee oletuksia, jotka estävät testin suorittamisen.
  • JUnit 5 tukee sisäkkäisiä ja dynaamisia testiluokkia.

Tutkimme suurimman osan näistä uusista ominaisuuksista tässä artikkelissa.

Yksikkötestaus JUnit 5: llä

Aloitetaan yksinkertaisella esimerkillä projektin määrittämisestä käyttämään JUnit 5: tä yksikötestissä. Luettelossa 1 näkyy a MathTools luokka, jonka menetelmä muuntaa osoittajan ja nimittäjän a: ksi kaksinkertainen.

Listaus 1. Esimerkki JUnit 5 -projektista (MathTools.java)

 paketti com.javaworld.geekcap.math; public class MathTools {public static double convertToDecimal (int-osoittaja, int-nimittäjä) {if (nimittäjä == 0) {heitä uusi IllegalArgumentException ("Nimittäjä ei saa olla 0"); } paluu (kaksois) osoittaja / (kaksois) nimittäjä; }}

Meillä on kaksi ensisijaista skenaariota MathTools luokka ja sen menetelmä:

  • A kelvollinen testi, jossa välitämme nollasta poikkeavat kokonaisluvut osoittajalle ja nimittäjälle.
  • A epäonnistumisskenaario, jossa välitämme nimittäjän nolla-arvon.

Luettelossa 2 näkyy JUnit 5 -testiluokka näiden kahden skenaarion testaamiseksi.

Listaus 2. JUnit 5 -testiluokka (MathToolsTest.java)

 paketti com.javaworld.geekcap.math; tuo java.lang.IllegalArgumentException; tuo org.junit.jupiter.api.Assertions; tuo org.junit.jupiter.api.Test; class MathToolsTest {@Test void testConvertToDecimalSuccess () {double tulos = MathTools.convertToDecimal (3, 4); Assertions.assertEquals (0,75, tulos); } @Test void testConvertToDecimalInvalidDenominator () {Assertions.assertThrows (IllegalArgumentException.class, () -> MathTools.convertToDecimal (3, 0)); }}

Luettelossa 2 testConvertToDecimalInvalidDenominator menetelmä suorittaa MathTools :: convertToDecimal menetelmä sisällä assertThrows puhelu. Ensimmäinen argumentti on odotettavissa oleva poikkeustyyppi. Toinen argumentti on funktio, joka tuo kyseisen poikkeuksen. assertThrows method suorittaa toiminnon ja vahvistaa, että odotettu poikkeustyyppi heitetään.

Väitteet-luokka ja sen menetelmät

org.junit.jupiter.api.Test merkintä tarkoittaa testimenetelmää. Huomaa, että @Testata merkinnät tulevat nyt JUnit 5 Jupiter -sovellusliittymäpaketista JUnit 4: n sijaan org.junit paketti. testConvertToDecimalSuccess menetelmä suorittaa ensin MathTools :: convertToDecimal menetelmä, jossa on osoittaja 3 ja nimittäjä 4, väittää sitten, että tulos on yhtä suuri kuin 0,75. org.junit.jupiter.api.Väitteet luokka tarjoaa joukon staattinen menetelmät todellisten ja odotettujen tulosten vertaamiseksi. Väitteet luokassa on seuraavat menetelmät, jotka kattavat suurimman osan primitiivisistä tietotyypeistä:

  • assertArrayEquals vertaa todellisen taulukon sisältöä odotettuun matriisiin.
  • väitäEquals vertaa todellista arvoa odotettuun arvoon.
  • assertNotEquals vertaa kahta arvoa vahvistaakseen, että ne eivät ole yhtä suuria.
  • väitäTosi vahvistaa, että annettu arvo on totta.
  • assertFalse vahvistaa, että annettu arvo on väärä.
  • assertLinesMatch vertaa kahta luetteloa Merkkijonos.
  • vakuuttaaNull vahvistaa, että annettu arvo on nolla.
  • assertNotNull vahvistaa, että annettu arvo ei ole nolla.
  • väittääSama vahvistaa, että kaksi arvoa viittaavat samaan objektiin.
  • assertNotSame vahvistaa, että kaksi arvoa eivät viittaa samaan objektiin.
  • assertThrows vahvistaa, että menetelmän toteutus heittää odotetun poikkeuksen (näet sen testConvertToDecimalInvalidDenominator yllä oleva esimerkki).
  • assertTimeout vahvistaa, että toimitettu toiminto suoritetaan tietyssä aikakatkaisussa.
  • assertTimeoutPreemptively vahvistaa, että toimitettu toiminto suoritetaan tietyssä aikakatkaisussa, mutta kun aikakatkaisu on saavutettu, se tappaa toiminnon suorituksen.

Jos jokin näistä väitemenettelyistä epäonnistuu, yksikkötesti merkitään epäonnistuneeksi. Tämä vikailmoitus kirjoitetaan näyttöön, kun suoritat testin, ja tallennetaan sitten raporttitiedostoon.

Deltan käyttäminen assertEqualsin kanssa

Käytettäessä kellua ja kaksinkertainen arvot väitäEquals, voit myös määrittää a delta joka edustaa näiden kahden välisen eron kynnystä. Esimerkissämme olisimme voineet lisätä delta-arvon 0,001, jos 0,75 palautettiin tosiasiallisesti arvona 0,750001.

Testitulosten analysointi

Arvon tai käyttäytymisen vahvistamisen lisäksi väittävät menetelmillä voidaan hyväksyä myös virheen tekstikuvaus, mikä voi auttaa vikojen diagnosoinnissa. Esimerkiksi:

 Assertions.assertEquals (0,75, tulos, "MathTools :: convertToDecimal-arvo ei palauttanut oikeaa arvoa 0,75 arvolle 3/4"); Assertions.assertEquals (0,75, tulos, () -> "MathTools :: convertToDecimal-arvo ei palauttanut oikeaa arvoa 0,75 arvolle 3/4"); 

Tuotos näyttää odotetun arvon 0,75 ja todellisen arvon. Se näyttää myös määritetyn viestin, mikä voi auttaa sinua ymmärtämään virheen kontekstin. Kahden muunnelman ero on siinä, että ensimmäinen luo aina viestin, vaikka sitä ei näytetä, kun taas toinen rakentaa viestin vain, jos väite epäonnistuu. Tässä tapauksessa viestin rakenne on vähäpätöinen, joten sillä ei ole väliä. Silti ei tarvitse rakentaa virheilmoitusta läpäisevälle testille, joten on yleensä parasta käyttää toista tyyliä.

Lopuksi, jos käytät testien suorittamiseen InteliJ: n kaltaista IDE: tä, kukin testimenetelmä näkyy sen menetelmän nimellä. Tämä on hieno, jos menetelmien nimet ovat luettavissa, mutta voit myös lisätä a @Näyttönimi merkintä testimenetelmistäsi testien tunnistamiseksi paremmin:

@Test @DisplayName ("Test onnistunut desimaalimuunnos") void testConvertToDecimalSuccess () {kaksoistulos = MathTools.convertToDecimal (3, 4); Assertions.assertEquals (0,751, tulos); }

Suorita yksikkötesti

Jotta voit suorittaa JUnit 5 -testit Maven-projektista, sinun on sisällytettävä maven-surefire-laajennus Mavenissa pom.xml tiedosto ja lisää uusi riippuvuus. Luettelossa 3 näkyy pom.xml tiedosto tähän projektiin.

Listaus 3. Maven pom.xml esimerkin JUnit 5 -projektille

  4.0.0 com.javaworld.geekcap junit5 jar 1.0-SNAPSHOT org.apache.maven.plugins maven-compiler-plugin 3.8.1 8 8 org.apache.maven.plugins maven-surefire-plugin 3.0.0-M4 junit5 // maven.apache.org org.junit.jupiter junit-jupiter 5.6.0 -testi 

JUnit 5 -riippuvuudet

JUnit 5 pakkaa komponentit org.junit.jupiter ryhmä ja meidän on lisättävä junit-jupiter artefakti, joka on aggregaattiartefakti, joka tuo seuraavat riippuvuudet:

  • junit-jupiter-api määrittelee API testien ja laajennusten kirjoittamiseen.
  • junit-jupiter-moottori on testimoottorin toteutus, joka suorittaa yksikötestit.
  • junit-jupiter-params tarjoaa tukea parametroiduille testeille.

Seuraavaksi meidän on lisättävä maven-surefire-laajennus rakentaa laajennus testien suorittamista varten.

Lopuksi, muista sisällyttää maven-kääntäjä-laajennus Java 8: n tai uudemman version kanssa, jotta voit käyttää Java 8: n ominaisuuksia, kuten lambdas.

Suorita se!

Käytä seuraavaa komentoa testiluokan suorittamiseen IDE: stä tai Mavenista:

mvn puhdas testi

Jos onnistut, sinun pitäisi nähdä seuraavanlainen tulos:

 [INFO] ----------------------------------------------- -------- [INFO] TESTIT [INFO] ----------------------------------- -------------------- [INFO] Suoritetaan com.javaworld.geekcap.math.MathToolsTest [INFO] Testit suoritetaan: 2, Viat: 0, Virheet: 0, Ohitettu : 0, Kulunut aika: 0,04 s - com.javaworld.geekcap.math.MathToolsTest [INFO] [INFO] Tulokset: [INFO] [INFO] Testit suoritettu: 2, Virheet: 0, Virheet: 0, Ohitettu: 0 [ INFO] [INFO] --------------------------------------------- --------------------------- [INFO] RAKENNA MENESTYKSET [INFO] --------------- -------------------------------------------------- ------- [INFO] Kokonaisaika: 3.832 s [INFO] Valmis: 2020-02-16T08: 21: 15-05: 00 [INFO] ------------- -------------------------------------------------- --------- 
$config[zx-auto] not found$config[zx-overlay] not found