Programiranje

Vadnica za JUnit 5, 1. del: Enotno testiranje z JUnit 5, Mockito in Hamcrest

JUnit 5 je novi de facto standard za razvijanje enotnih testov v Javi. Ta najnovejša različica je za seboj pustila omejitve Java 5 in integrirala številne funkcije Java 8, predvsem podporo za lambda izraze.

V tej prvi polovici dvodelnega uvoda v JUnit 5 boste začeli s testiranjem z JUnit 5. Pokazal vam bom, kako konfigurirati projekt Maven za uporabo JUnit 5, kako pisati teste z uporabo @Test in @ParameterizedTest in kako delati z novimi pripisi v življenjskem ciklu v JUnit 5. Videli boste tudi kratek primer uporabe oznak filtra in pokazal vam bom, kako JUnit 5 integrirati s knjižnico trditev drugih proizvajalcev - v tem primeru , Hamcrest. Na koncu boste dobili hiter uvod v integracijo JUnit 5 z Mockito, tako da boste lahko napisali bolj robustne enote za kompleksne resnične sisteme.

prenos Pridobite kodo Pridobite izvorno kodo za primere v tej vadnici. Ustvaril Steven Haines za JavaWorld.

Testno voden razvoj

Če že kdaj razvijate kodo Java, ste verjetno dobro seznanjeni s testnim razvojem, zato bom ta odsek na kratko. Pomembno je razumeti zakaj pišemo enotne teste, pa tudi strategije, ki jih razvijalci uporabljajo pri oblikovanju enotnih testov.

Test-driven development (TDD) je postopek razvoja programske opreme, ki prepleta kodiranje, testiranje in oblikovanje. To je preizkusni pristop, katerega cilj je izboljšati kakovost vaših aplikacij. Testno usmerjen razvoj je opredeljen z naslednjim življenjskim ciklom:

  1. Dodajte test.
  2. Zaženite vse teste in opazujte, da novi test ne uspe.
  3. Uporabite kodo.
  4. Zaženite vse teste in opazujte, kako novi test uspe.
  5. Refaktor kode.

Slika 1 prikazuje ta življenjski cikel TDD.

Steven Haines

Pisanje testov pred pisanjem kode ima dvojni namen. Najprej vas prisili k razmišljanju o poslovnem problemu, ki ga želite rešiti. Na primer, kako naj se obnašajo uspešni scenariji? Kateri pogoji bi morali propasti? Kako naj propadejo? Drugič, najprej vam testiranje daje več zaupanja v svoje teste. Kadar pišem teste po pisanju kode, jih moram vedno razbiti, da se prepričam, da dejansko lovijo napake. Pisanje testov se najprej izogne ​​dodatnemu koraku.

Pisanje testov za srečno pot je običajno enostavno: ob dobrem vnosu bi moral razred vrniti deterministični odziv. Toda pisanje negativnih (ali neuspešnih) testnih primerov, zlasti za kompleksne komponente, je lahko bolj zapleteno.

Kot primer razmislite o pisanju testov za repozitorij baze podatkov. Na srečni poti v bazo vstavimo zapis in prejmemo nazaj ustvarjeni predmet, vključno z morebitnimi ustvarjenimi ključi. V resnici moramo upoštevati tudi možnost konflikta, na primer vstaviti zapis z edinstveno vrednostjo stolpca, ki ga že ima drug zapis. Poleg tega, kaj se zgodi, ko se skladišče ne more povezati z bazo podatkov, morda zato, ker se je spremenilo uporabniško ime ali geslo? Kaj se zgodi, če pri prevozu pride do omrežne napake? Kaj se zgodi, če se zahteva ne izpolni v določeni časovni omejitvi?

Če želite zgraditi robustno komponento, morate upoštevati vse verjetne in verjetne scenarije, zanje razviti teste in napisati kodo, ki bo zadovoljila te teste. Kasneje v članku bomo preučili strategije za ustvarjanje različnih scenarijev okvar, skupaj z nekaterimi novimi funkcijami v JUnit 5, ki vam lahko pomagajo pri preizkusu teh scenarijev.

Sprejetje JUnit 5

Če že nekaj časa uporabljate JUnit, bodo nekatere spremembe v JUnit 5 prilagoditev. Tu je povzetek na visoki ravni, kaj se razlikuje med obema različicama:

  • JUnit 5 je zdaj zapakiran v org.junit.jupiter group, kar spremeni način, kako ga boste vključili v svoje projekte Maven in Gradle.
  • JUnit 4 je zahteval najmanj JDK 5 JDK; JUnit 5 zahteva najmanj 8 JDK.
  • JUNIT 4 @ Pred tem, @BeforeClass, @Po, in @Po pouku pripisi so bili nadomeščeni z @BeforeEach, @BeforeAll, @AfterEach, in @Konec koncevoziroma.
  • JUNIT 4 @ Prezri pripis je bil nadomeščen z @Onemogočeno pripis.
  • The @Kategorija pripis je bil nadomeščen z @Oznaka pripis.
  • JUnit 5 doda nov nabor metod uveljavljanja.
  • Tekači so bili zamenjani z razširitvami, z novim API-jem za izvedbe razširitev.
  • JUnit 5 uvaja predpostavke, ki ustavijo izvajanje testa.
  • JUnit 5 podpira vgnezdene in dinamične preizkusne razrede.

Večino teh novih funkcij bomo raziskali v tem članku.

Enotno testiranje z JUnit 5

Začnimo preprosto, s primerom konfiguriranja projekta za uporabo JUnit 5 za preskus enote. Seznam 1 prikazuje a MathTools razred, katerega metoda pretvori števec in imenovalec v dvojno.

Seznam 1. Primer projekta JUnit 5 (MathTools.java)

 paket com.javaworld.geekcap.math; javni razred MathTools {javni statični dvojni convertToDecimal (int števec, int imenovalec) {if (imenovalec == 0) {vrzi novo IllegalArgumentException ("Imenovalec ne sme biti 0"); } vrniti (dvojni) števec / (dvojni) imenovalec; }}

Za preskušanje imamo dva glavna scenarija MathTools razred in njegova metoda:

  • A veljaven test, v katerem za števec in imenovalec posredujemo cela števila, ki niso nič.
  • A scenarij okvare, v katerem za imenovalec prenesemo ničto vrednost.

Seznam 2 prikazuje preskusni razred JUnit 5 za preizkušanje teh dveh scenarijev.

Seznam 2. Preskusni razred JUnit 5 (MathToolsTest.java)

 paket com.javaworld.geekcap.math; import java.lang.IllegalArgumentException; uvoz org.junit.jupiter.api.Trditve; uvoz org.junit.jupiter.api.Test; razred MathToolsTest {@Test void testConvertToDecimalSuccess () {dvojni rezultat = MathTools.convertToDecimal (3, 4); Assertions.assertEquals (0,75, rezultat); } @Test void testConvertToDecimalInvalidDenominator () {Assertions.assertThrows (IllegalArgumentException.class, () -> MathTools.convertToDecimal (3, 0)); }}

V seznamu 2 je testConvertToDecimalInvalidDenominator metoda izvrši MathTools :: convertToDecimal metoda znotraj assertThrows pokličite. Prvi argument je pričakovana vrsta izjeme. Drugi argument je funkcija, ki bo vrgla to izjemo. The assertThrows metoda izvrši funkcijo in preveri, ali je vržena pričakovana vrsta izjeme.

Razred Assertions in njegove metode

Theorg.junit.jupiter.api.Test oznaka označuje preskusno metodo. Upoštevajte, da @Test opomba zdaj prihaja iz paketa JUnit 5 Jupiter API namesto JUnit 4 org.junit paket. The testConvertToDecimalSuccess metoda najprej izvede MathTools :: convertToDecimal metoda s števcem 3 in imenovalcem 4, nato trdi, da je rezultat enak 0,75. The org.junit.jupiter.api.Trditve razred ponuja nabor statično metode za primerjavo dejanskih in pričakovanih rezultatov. The Trditve class ima naslednje metode, ki pokrivajo večino primitivnih podatkovnih vrst:

  • assertArrayEquals primerja vsebino dejanskega polja s pričakovanim nizom.
  • assertEquals primerja dejansko vrednost s pričakovano vrednostjo.
  • assertNotEquals primerja dve vrednosti, da potrdi, da nista enaki.
  • assertTrue preveri, ali je navedena vrednost resnična.
  • assertFalse potrdi, da je navedena vrednost napačna.
  • assertLinesMatch primerja dva seznama Vrvicas.
  • assertNull potrdi, da je navedena vrednost nična.
  • assertNotNull potrdi, da navedena vrednost ni nič.
  • assertSame preveri, da se dve vrednosti nanašata na isti objekt.
  • assertNotSame preveri, da se dve vrednosti ne nanašata na isti objekt.
  • assertThrows potrjuje, da izvajanje metode vrže pričakovano izjemo (to lahko vidite v testConvertToDecimalInvalidDenominator primer zgoraj).
  • assertTimeout preveri, ali se dobavljena funkcija dokonča v določenem času.
  • assertTimeoutPreempitive preveri, ali se dobavljena funkcija zaključi v določenem časovnem poteku, a ko je dosežen, prekine izvajanje funkcije.

Če katera od teh trditev ne uspe, je preskus enote označen kot neuspešen. To obvestilo o napaki bo zapisano na zaslon, ko zaženete preizkus, nato pa shranjeno v datoteki poročila.

Uporaba delte z assertEquals

Pri uporabi plovec in dvojno vrednosti v assertEquals, lahko določite tudi delta ki predstavlja prag razlike med obema. V našem primeru bi lahko dodali delto 0,001, če bi bilo 0,75 dejansko vrnjeno kot 0,750001.

Analiziranje rezultatov testa

Poleg preverjanja vrednosti ali vedenja, trditi metode lahko sprejmejo tudi besedilni opis napake, ki vam lahko pomaga pri diagnosticiranju napak. Na primer:

 Assertions.assertEquals (0,75, rezultat, "Vrednost MathTools :: convertToDecimal ni vrnila pravilne vrednosti 0,75 za 3/4"); Assertions.assertEquals (0,75, rezultat, () -> "Vrednost MathTools :: convertToDecimal ni vrnila pravilne vrednosti 0,75 za 3/4"); 

Rezultat bo prikazal pričakovano vrednost 0,75 in dejansko vrednost. Prikazalo se bo tudi določeno sporočilo, ki vam lahko pomaga razumeti kontekst napake. Razlika med obema različicama je v tem, da prva vedno ustvari sporočilo, tudi če ni prikazano, druga pa sporočilo ustvari le, če trditev ne uspe. V tem primeru je konstrukcija sporočila nepomembna, zato v resnici ni pomembno. Kljub temu ni treba ustvariti sporočila o napaki za preizkus, ki je uspešno opravljen, zato je običajno najboljša praksa, da uporabimo drugi slog.

Nazadnje, če za izvajanje testov uporabljate IDE, kot je IntelliJ, bo vsaka testna metoda prikazana z imenom metode. To je v redu, če so imena metod berljiva, lahko pa dodate tudi @DisplayName pripis k testnim metodam, da jih bolje prepoznate:

@Test @DisplayName ("Testiraj uspešno decimalno pretvorbo") void testConvertToDecimalSuccess () {dvojni rezultat = MathTools.convertToDecimal (3, 4); Assertions.assertEquals (0,751, rezultat); }

Izvajanje testa enote

Če želite zagnati teste JUnit 5 iz projekta Maven, morate vključiti maven-surefire-plugin v Mavenu pom.xml datoteko in dodajte novo odvisnost. Seznam 3 prikazuje pom.xml datoteka za ta projekt.

Seznam 3. Maven pom.xml za primer projekta JUnit 5

  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 test 

JUNIT 5 odvisnosti

JUnit 5 pakira svoje komponente v org.junit.jupiter skupini in moramo dodati junit-jupiter artefakt, ki je zbirni artefakt, ki uvaža naslednje odvisnosti:

  • junit-jupiter-api definira API za pisanje testov in razširitev.
  • junit-jupiter-motor je izvedba preizkusnega motorja, ki izvaja preskuse enot.
  • junit-jupiter-params zagotavlja podporo za parametrizirane teste.

Nato moramo dodati maven-surefire-plugin zgraditi vtičnik za izvajanje preskusov.

Na koncu vključite tudi maven-compiler-plugin z različico Java 8 ali novejšo, tako da boste lahko uporabljali funkcije Java 8, kot so lambda.

Zaženi!

Z naslednjim ukazom zaženite preskusni razred iz IDE ali Mavena:

mvn čisti test

Če ste uspešni, bi morali videti rezultate, podobne naslednjim:

 [INFO] ------------------------------------------------ -------- [INFO] PRESKUSI [INFO] ----------------------------------- -------------------- [INFO] Izvajanje com.javaworld.geekcap.math.MathToolsTest [INFO] Izvedeni testi: 2, napake: 0, napake: 0, preskočeno : 0, potekel čas: 0,04 s - v com.javaworld.geekcap.math.MathToolsTest [INFO] [INFO] Rezultati: [INFO] [INFO] Izvedeni testi: 2, neuspehi: 0, napake: 0, preskočeni: 0 [ INFO] [INFO] --------------------------------------------- --------------------------- [INFO] ZGRADI USPEH [INFO] --------------- -------------------------------------------------- ------- [INFO] Skupni čas: 3.832 s [INFO] Končano ob: 2020-02-16T08: 21: 15-05: 00 [INFO] ------------- -------------------------------------------------- --------- 
$config[zx-auto] not found$config[zx-overlay] not found