Junit:Otvoreni okvir Java testiranja jedinica
01, Prošlost i sadašnjost
Zdravo, ja sam JUnit, otvoreni okvir Java testiranja jedinica. Pre nego što me upoznate, prvo da upoznate šta je testiranje jedinica. Testiranje jedinica, to jest pišemo test kod za najmanje funkcionalne jedinice. U Java, najmanja funkcionalna jedinica je metoda, zato, za Java programere testiranje jedinica zapravo testira Java metode.
Zašto treba raditi testiranje jedinica? Jer testiranje jedinica može osigurati da je kod koji pišete u skladu sa softverskim zahtevima i sledi razvojne standarde. Testiranje jedinica je najniži nivo testova među svim testovima, prva karika, i najvažnija karika, jedini put da se postiže poklritost koda 100%, osnova i preduvet celog procesa testiranja softvera. Može se reći, odnos cene i koristi testiranja jedinica je najbolji.
Kompanija Microsoft ranije je imala jednu statistiku: bug koji je otkriven u fazi testiranja jedinica prosečno troši 3.25 sata, ako se propusti do sistemskog testa tada treba 11.5 sati.

Nakon što sam vam ovako rekao, trebalo bi da veoma jasno razumete važnost testiranja jedinica. Ali kada prvi put pišete test kod, često li radite ovako? Kao donji.
public class Factorial {
public static long fact(long n) {
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
public static void main(String[] args) {
if (fact(3) == 6) {
System.out.println("Prošlo");
} else {
System.out.println("Neuspelo");
}
}
}Da testirate tačnost metoda fact(), u metodi main() ste napisali jedan test kod. Ako ste ovako radili, mogu samo reći da ste i vi bili naivni i jednostavni! Korišćenje metoda main() za testiranje ima mnoge mane, na primer:
Test kod nije odvojen od izvornog koda.
Nije dovoljno fleksibilno, teško je napisati grupu opšti test kod.
Ne može automatski ispisati očekivane i stvarne rezultate, nema načina za poređenje.
Ali ako naučite da koristite mene – JUnit, onda nećete imati ovu mućnju. Ja mogu veoma jednostavno organizovati test kod, i u svakom trenutku pokretati ih, i dati precizan test izveštaj, omogućiti vam da u najkraćem vremenu otkrijte gde je problem u kodu koji ste napisali.
02, Vodič za upotrebu
Dobro, pošto sada znate da sam tako odličan, šta čekate, direktno počnite! Moja najnovija verzija je JUnit 5, Intellij IDEA me je integrisala, zato možete direktno u IDEA pisati i pokretati moje test slučajeve.
Prvi korak, direktno u trenutnom prozoru za uređivanje koda pritisnite Command+N taster (Mac verzija), u iskočkom meniju izaberite "Test...".

Označite metodu fact() za koju želite da napišete test slučaj, zatim kliknite "U redu".
U ovom trenutku, IDEA će automatski generisati test klasu sa imenom sa Test (konvencija) u paketu trenutne klase. Kao na sledećoj slici.

Ako ste prvi put koristili mene, IDEA će vas podsetiti da uvezete moje pakete zavisnosti. Predlažem da izaberete najnoviji JUnit 5.4.

Nakon uvoza, možete otvoriti fajl pom.xml da potvrdite, unutra je dodata zavisnost na mene.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>Drugi korak, dodajte grupu tvrdnji u test metodu, kao sledeće.
@Test
void fact() {
assertEquals(1, Factorial.fact(1));
assertEquals(2, Factorial.fact(2));
assertEquals(6, Factorial.fact(3));
assertEquals(100, Factorial.fact(5));
}@Test anotacija je m zahtev, ja ću prepoznati metode sa @Test kao test metode. U test metodi, možete koristiti assertEquals() da uporedite očekivane vrednosti i stvarne vrednosti.
Treći korak, možete u meniju e-pošte izabrati "Run FactorialTest" da pokrenete test slučaj, rezultat je kao sledeći.

Test je neuspešan, jer očekivani rezultat u 20. liniji se ne slaža sa stvarnim, očekivano je 100, stvarno je 120. U ovom trenutku, ili ispravite implementacioni kod, ili ispravite test kod, dok test ne prođe.

Nije teško, zar ne? Testiranje jedinica može osigurati da pojedinačne metode rade ispravno po očekivanju, ako ste izmenili kod jedne metode, samo osigurajte da odgovarajući test jedinice prođe, tada možete smatrati da izmene nemaju problema.
03, Gledaj unapred i unazad
U jednom test slučaju, možda treba testirati više metoda. Pre testiranja, treba pripremiti neke uslove, na primer kreirati objekte; nakon završetka testiranja, treba te objekte uništiti da oslobodite resurse. Ako ponovite ove šablone koda u više test metoda, će se činiti veoma dosadno.
U ovom trenutku, šta treba raditi?
Ja vam pružam setUp() i tearDown(), kao edukovanog čoveka, ja to zovem "gledaj unapred i unazad". Hajde da vidimo kod koji treba testirati.
public class Calculator {
public int sub(int a, int b) {
return a - b;
}
public int add(int a, int b) {
return a + b;
}
}Kada kreirate novi test slučaj, obavezno označite setUp i tearDown.

Generisani kod je kao sledeći.
class CalculatorTest {
Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@AfterEach
void tearDown() {
calculator = null;
}
@Test
void sub() {
assertEquals(0,calculator.sub(1,1));
}
@Test
void add() {
assertEquals(2,calculator.add(1,1));
}
}@BeforeEach metoda setUp() će se pokrenuti pre pokretanja svake metode @Test; metoda tearDown() sa @AfterEach će se pokrenuti nakon pokretanja svake metode @Test.
S tim odgovaraju i @BeforeAll i @AfterAll, razlikuju se od @BeforeEach i @AfterEach, All se obično koristi za inicijalizaciju i uništenje statičkih promenljivih.
public class DatabaseTest {
static Database db;
@BeforeAll
public static void init() {
db = createDb(...);
}
@AfterAll
public static void drop() {
...
}
}03, Testiranje izuzetaka
Za Java programe, rukovanje izuzecima je takođe veoma važno. Testiranje mogućih izuzetaka je takođe važna karika testiranja.
Još uvek koristimo raniju klasu Factorial za objašnjenje. Na početku metode fact(), vrši se validacija parametra n, ako je manji od 0, baca izuzetak IllegalArgumentException.
public class Factorial {
public static long fact(long n) {
if (n < 0) {
throw new IllegalArgumentException("Parametar ne može biti manji od 0");
}
long r = 1;
for (long i = 1; i <= n; i++) {
r = r * i;
}
return r;
}
}U FactorialTest dodajte test metodu factIllegalArgument().
@Test
void factIllegalArgument() {
assertThrows(IllegalArgumentException.class, new Executable() {
@Override
public void execute() throws Throwable {
Factorial.fact(-2);
}
});
}Ja vam pružam metodu assertThrows(), prvi parametar je tip izuzetka, drugi parametar Executable, može enkapsulirati kod koji baca izuzetak. Ako mislite da je pisanje anonimnih unutrašnjih klasa komplikovano, možete koristiti Lambda izraze.
@Test
void factIllegalArgumentLambda() {
assertThrows(IllegalArgumentException.class, () -> {
Factorial.fact(-2);
});
}04, Ignoriši test
Ponekad, iz razloga, neke metode imaju bag, treba vremena da se poprave, pre popravke, odgovarajući test slučajevi tih metoda uvek se završavaju neuspehom, da bi se izbegla ova situacija, ja vam pružam anotaciju @Disabled.
class DisabledTestsDemo {
@Disabled("Ovaj test slučaj se neće izvršiti, dok se bag broj 43 ne popravi")
@Test
void testWillBeSkipped() {
}
@Test
void testWillBeExecuted() {
}
}Anotacija @Disabled takođe može biti bez objašnjenja, ali ja predlažem da ipak date, jednostavno objasnite zašto ovu test metodu treba ignorisati. U gornjem primeru, ako drugi članovi tima vide objašnjenje, razumeće da se nakon što se bag broj 43 popravi, ova test metoda će ponovo biti omogućena. Čak i kao podsetnik za sebe, vrlo je neophodno, jer nakon dužeg vremena možete i sami zaboraviti, zašto ste originalno ignorisali ovu test metodu.
05, Uslovno testiranje
Ponekad, možda treba pokrenuti test metodu pod određenim uslovima, pod nekim uslovima ne pokrenuti test metodu. Za ovu scenu upotrebe, ja vam pružam uslovno testiranje.
- Različiti operativni sistemi, možda trebaju različiti test slučajevi, na primer putanje imena fajlova u Linuxu i Windowsu su različite, kroz anotaciju
@EnabledOnOsmože omogućiti različite test slučajeve za različite operativne sisteme.
@Test
@EnabledOnOs(MAC)
void onlyOnMacOs() {
// ...
}
@TestOnMac
void testOnMac() {
// ...
}
@Test
@EnabledOnOs({ LINUX, MAC })
void onLinuxOrMac() {
// ...
}
@Test
@DisabledOnOs(WINDOWS)
void notOnWindows() {
// ...
}- Različita Java okruženja za izvršavanje, možda takođe trebaju različiti test slučajevi. Anotacije
@EnabledOnJrei@EnabledForJreRangemogu zadovoljiti ovaj zahtev.
@Test
@EnabledOnJre(JAVA_8)
void onlyOnJava8() {
// ...
}
@Test
@EnabledOnJre({ JAVA_9, JAVA_10 })
void onJava9Or10() {
// ...
}
@Test
@EnabledForJreRange(min = JAVA_9, max = JAVA_11)
void fromJava9to11() {
// ...
}06, Epilog
Konačno, dajem vam tri reči iz srca. Kada pišete testove jedinice, najbolje je da radite ovako:
Kod testa jedinice mora biti vrlo jasan i razumljiv, može se odmah razumeti, ne može ponovo pisati test kod za test kod.
Svaki test jedinice treba da bude međusobno nezavisan, ne zavisi od redosleda izvršavanja pri izvršavanju.
Pri testiranju posebno obratite pažnju na granične uslove, na primer 0,
null, prazan string "" i slično.
Nadam se da mogu što ranije otkriti bag u vašem kodu, jer što ranije otkrije, manja će šteta. vidimo se!
