CodeGym /Blog Java /Aleatoriu /Testarea unitară în Java cu JUnit
John Squirrels
Nivel
San Francisco

Testarea unitară în Java cu JUnit

Publicat în grup

Ce este testarea unitară în Java?

Înainte de a începe să învățăm JUnit în Java, să vedem pe scurt ce este testarea unitară și de ce este atât de populară (dacă știți deja aceste lucruri, treceți la „Cum scriu un test JUnit în Java?”). Testarea unitară în Java face dezvoltarea de software pe scară largă mult mai eficientă și fără efort. Poate ajuta atât indivizii, cât și echipele să reducă nenumărate ore de depanare și să eficientizeze enorm procesul de colaborare. Testarea unitară în Java cu JUnit - 1

https://junit.org/junit4/

Ideea esențială a testării unitare este aceasta: scrieți teste atomice ale caracteristicilor individuale (numite teste unitare) și adăugați încet mai multe caracteristici după testare și asigurați-vă că cele anterioare funcționează. Este o idee extrem de simplă, dar puternică. Ca exemplu despre cum ar putea arăta acest proces, imaginați-vă că construiți un calculator științific virtual. Pe lângă operatorii aritmetici aparentați ( +, -, x, %), acest calculator ar avea caracteristici avansate care necesită alte subfuncții pentru a funcționa în el. Pentru a calcula exponenți, calculatorul trebuie să poată înmulți corect. Deci, o abordare de testare unitară pentru construirea și testarea acestui calculator ar fi:
  • Scrieți o funcție de adunare. Testează-l cu atenție, schimbă-l, repetă până funcționează.
  • Faceți același lucru pentru funcțiile de scădere, înmulțire, împărțire.
  • Utilizați acești operatori de bază pentru a scrie funcții de operator mai avansate, cum ar fi exponenții, apoi testați și acele funcții.
Acest lucru asigură că funcțiile care se bazează pe alte subfuncții mai mici nu numai că funcționează corect în sine, dar nu au subfuncții defecte în ele. De exemplu, dacă testez funcția exponent și ceva nu merge bine, știu că bug-ul probabil nu este în subfuncția de multiplicare, deoarece funcția de multiplicare a fost deja testată pe larg. Acest lucru elimină foarte mult cantitatea totală de cod pe care trebuie să o urmăresc și să o inspectez pentru a găsi eroarea. Sperăm că acest exemplu trivial arată clar cum este structurat procesul de gândire în jurul testării unitare. Dar cum interacționează testarea unitară cu restul procesului de dezvoltare software? Ce se întâmplă dacă aveți caracteristici și mai complexe, care trebuie să poată lucra și comunica împreună? Testarea unitară este insuficientă pentru a se asigura că astfel de caracteristici complexe pot funcționa corect împreună. De fapt, este doar primul pas al celor patru niveluri de testare a software-ului (folosesc majuscule pentru că mă refer la standardul industriei sau la cea mai comună abordare de testare a software-ului). Ultimii trei pași suntTestare de integrare , testare de sistem și testare de acceptare. Probabil toate acestea înseamnă exact ceea ce credeți că fac, dar permiteți-mi să clarific: testarea integrării este ceea ce am face pentru a ne asigura că cele menționate mai sus, „funcții complexe”, interacționează corect unele cu altele. (de exemplu, asigurați-vă că calculatorul poate gestiona „3 + 7 * 4 - 2”) Testarea sistemului înseamnă testarea designului general al unui anumit sistem; Există adesea mai multe sisteme de caracteristici complexe care lucrează împreună într-un produs, așa că le grupați în sisteme și le testați individual. (de exemplu, dacă ați construi un calculator grafic, mai întâi ați construi „sistemul” aritmetic pentru a se ocupa de numere, testând până când funcționează conform intenției, apoi ați construi și testa „sistemul” grafic pentru a face față retragerii, ca s-ar construi din sistemul aritmetic). Testarea de acceptare este testare la nivel de utilizator; este să vedem dacă toate sistemele pot funcționa sincronizat pentru a crea un produs finit gata să fie acceptat de utilizatori (de exemplu, utilizatorii care testează calculatorul). Dezvoltatorii de software pot ignora uneori acest pas final al procesului, deoarece companiile vor avea adesea alți angajați să implementeze teste de utilizator (beta) separat.

Cum scriu un test JUnit în Java?

Acum că aveți o idee mai clară despre beneficiile și limitările testării unitare, să aruncăm o privire la un cod! Vom folosi un cadru popular de testare Java numit JUnit (un altul popular este TestNG, pe care îl puteți folosi și dacă doriți. Sunt foarte asemănătoare, sintactic; TestNG este inspirat de JUnit). Puteți descărca și instala JUnit aici . Pentru acest exemplu de cod, vom continua de la exemplul „calculator științific” pe care îl menționam mai devreme; este destul de simplu să-ți faci cap, iar codul de testare este foarte ușor. Practica convențională este să scrieți clase de testare separate pentru fiecare dintre clasele dvs., așa că asta vom face. Să presupunem că în acest moment avem un Math.javafișier cu toate funcțiile matematice din el (inclusiv Math.add), și scriem unMathTests.javafișier în același pachet. Acum să setăm instrucțiunile de import și corpul clasei: (INTREBARE POSIBILĂ DE INTERVIU JUnit: Este posibil să vi se întrebe unde să plasați testul JUnit și dacă trebuie sau nu să importați fișierele sursă. Dacă scrieți clasele de testare în același pachet cu clasele dvs. principale, atunci nu aveți nevoie de instrucțiuni de import pentru fișierele sursă din clasa de testare. În caz contrar, asigurați-vă că importați fișierele sursă!)

import org.junit.jupiter.Test;    //gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; //less typing :) 

public class MathTests {
	//...
}
Prima instrucțiune de import ne oferă @Testantetul. Scriem „ @Test” direct deasupra definiției fiecărei funcții de testare, astfel încât JUnit să știe că acesta este un test unitar singular care poate fi rulat separat. Mai târziu, vă voi arăta cum puteți rula anumite teste unitare folosind acest antet. A doua instrucțiune de import ne scutește puțin de tastare. Funcția JUnit principală pe care o folosim pentru a ne testa funcțiile este to Assert.assertEquals(), care ia doi parametri (valoarea reală și valoarea așteptată) și se asigură că sunt egali. Având această a doua instrucțiune de import, ne permite doar să introducem „ assertEquals(...” în loc să trebuie să specificăm de fiecare dată din ce pachet face parte. Acum să scriem un caz de test foarte simplu pentru a verifica că 2 + 2 este într-adevăr 4!

import org.junit.jupiter.Test; // gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; // less typing :) 


public class MathTests {
	@Test
	public void add_twoPlusTwo_returnsFour(){
	final int expected = 4;
	final int actual = Math.add(2, 2);
	assertEquals(“2+2 is 4”, actual, expected);
	}
}
Să trecem peste fiecare dintre cele cinci linii ale funcției de testare și ce fac acestea: Linia 5: Acest @Testantet specifică că definiția funcției de mai jos add_twoPlusTwo_returnsFour()este într-adevăr o funcție de testare pe care JUnit o poate rula separat. Linia 6: Aceasta este semnătura funcției pentru cazul nostru de testare. Cazurile de testare sunt întotdeauna foarte singulare; ei testează doar un exemplu specific, cum ar fi 2+2=4. Este convenție să denumiți cazurile de testare în forma „ [function]_[params]_returns[expected]()”, unde [function]este numele funcției pe care o testați, [params]sunt exemplele de parametri specifici pe care îi testați și [expected]este valoarea de returnare așteptată a funcției. Funcțiile de testare au aproape întotdeauna un tip de returnare de „ void” deoarece scopul principal al întregii funcții este rulareaassertEquals, care va ieși pe consolă indiferent dacă testul a trecut sau nu; nu aveți nevoie de alte date pentru a fi returnate nicăieri. Linia 7: Declaram o finalvariabila ' ' de tipul returnat de Math.add (int), si o denumim prin conventie 'aşteptat'. Valoarea lui este răspunsul pe care îl așteptăm (4). Linia 8: Declaram o finalvariabila ' ' de tipul returnat de Math.add (int), si o numim 'actual' prin conventie. Valoarea sa este rezultatul Math.add(2, 2). Linia 9: Linia de aur. Aceasta este linia care compară realul și cel așteptat și ne spune că am trecut testul numai dacă sunt egale. Primul parametru trecut „2+2 este 4” este o descriere a funcției de testare.

Ce se întâmplă dacă funcția mea ar trebui să arunce o excepție?

Dacă exemplul dvs. de test specific ar trebui să arunce o excepție în loc să afirme că o valoare reală și cea așteptată sunt egale, atunci JUnit are o modalitate de a clarifica acest lucru în antet @Test. Să aruncăm o privire la un exemplu de mai jos. Presupunând că avem o funcție în Math.javacall Math.divide, dorim să ne asigurăm că intrările nu pot fi împărțite la 0. În schimb, încercarea de a apela Math.divide(a, 0)orice valoare „a” ar trebui să arunce o excepție ( ArithmeticException.class). Specificăm astfel în antet astfel:

import org.junit.jupiter.Test; // gives us the @Test header
import static org.junit.jupiter.api.Assertions.assertEquals; // less typing :) 


public class MathTests {
	@Test (expectedExceptions = ArithmeticException.class)
	public void divide_byZero_throwsException() throws ArithmeticException{
	Math.divide(1, 0);
	}
}
Puteți avea mai multe excepții pentru expectedExceptions, doar asigurați-vă că utilizați paranteze și virgule pentru a lista clasele de excepție, ca atare:

expectedException = {FirstException.class, SecondException.class, … }

Cum îmi rulez testele JUnit în Java?

Cum să adăugați JUnit la IntelliJ: https://stackoverflow.com/questions/19330832/setting-up-junit-with-intellij-idea Vă puteți rula proiectul așa cum ați rula în mod normal testele. Rularea tuturor testelor dintr-o clasă de testare le va rula în ordine alfabetică. În JUnit 5, puteți adăuga o prioritate la teste adăugând o @Orderetichetă. Un exemplu:

@TestMethodOrder(OrderAnnotation.class)
public class Tests {
…
@Test
@Order(2)
public void a_test() { … }

@Test
@Order (1)
public void b_test() { … }
…
}
Chiar dacă a_test()apare înainte b_test()alfabetic și în cod, b_test()va rula înainte de a_test()aici, deoarece 1 vine înaintea lui 2 în ordine. Deci, cam atât pentru elementele de bază ale JUnit. Acum, să abordăm câteva întrebări obișnuite de interviu JUnit și să aflăm mai multe despre JUnit pe parcurs!

Întrebări de interviu JUnit (informații suplimentare)

Aici am adunat cele mai populare întrebări de interviu JUnit. Dacă aveți ceva de adăugat, nu ezitați să faceți acest lucru în comentariile de mai jos. Î: Ce metodă puteți apela la metoda de testare pentru a eșua automat un test? A: fail(„descrierea erorii aici!”); Î: Testați o clasă de câini; pentru a testa un obiect Dog, trebuie să-l instanțiați înainte de a putea rula teste pe el. Deci scrieți o funcție setUp() pentru a instanția Câinele. Doriți să rulați această funcție o singură dată în timpul tuturor testării. Ce trebuie să puneți direct deasupra semnăturii funcției setUp() pentru ca JUnit să știe să ruleze setUp() înainte de a rula testele? R: @BeforeClass (@BeforeAll în JUnit 5) Î:Care trebuie să fie semnătura funcției setUp() descrisă mai sus? A: vid static public. Orice funcție cu @BeforeClass (@BeforeAll în JUnit 5) sau @AfterClass (@AfterAll în JUnit 5) trebuie să fie statică. Î: Ai terminat de testat clasa de câini. Scrieți funcția void tearDown() care curăță datele și imprimă informații pe consolă după fiecare test. Doriți ca această funcție să ruleze după fiecare test. Ce trebuie să puneți direct deasupra semnăturii funcției tearDown() pentru ca JUnit să știe să ruleze tearDown() după rularea fiecărui test? R: @After (@AfterEach în JUnit 5)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION