Testarea unitară

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 23 martie 2020; verificarea necesită 21 de modificări .

Testarea unitară , uneori testarea unitară sau testarea unitară ( de exemplu, testarea  unitară ) este un proces de programare care vă permite să verificați corectitudinea modulelor individuale ale codului sursă al programului , seturi de unul sau mai multe module de program, împreună cu datele de control corespunzătoare, proceduri de utilizare și procesare.

Ideea este de a scrie teste pentru fiecare funcție sau metodă non-trivială. Acest lucru vă permite să verificați rapid dacă următoarea modificare a codului a dus la regresie , adică la apariția erorilor în locurile deja testate ale programului și facilitează, de asemenea, detectarea și eliminarea unor astfel de erori. De exemplu, puteți actualiza în orice moment biblioteca utilizată în proiect la versiunea curentă, rulând teste și identificând incompatibilitățile.

Beneficii

Scopul testării unitare este de a izola părțile individuale ale unui program și de a arăta că acele părți funcționează individual.

Acest tip de testare este de obicei făcut de programatori .

Schimbarea încurajatoare

Testarea unitară ulterioară le permite programatorilor să refactoreze în timp ce sunt siguri că unitatea încă funcționează corect ( testarea regresiei ). Acest lucru încurajează programatorii să schimbe codul, deoarece este suficient de ușor să verificați dacă codul încă funcționează după modificare.

Integrare mai ușoară

Testarea unitară ajută la eliminarea îndoielilor cu privire la modulele individuale și poate fi utilizată pentru o abordare de jos în sus a testării: testarea mai întâi a părților individuale ale programului și apoi a programului ca întreg.

Documentația codului

Testele unitare pot fi gândite ca un „document viu” pentru clasa testată . Clienții care nu știu să folosească această clasă pot folosi testul unitar ca exemplu.

Separarea interfeței de implementare

Deoarece unele clase pot folosi alte clase, testarea unei singure clase se extinde adesea la clasele înrudite. De exemplu, o clasă folosește o bază de date; în timp ce scrie un test, programatorul descoperă că testul trebuie să interacționeze cu baza de date. Aceasta este o eroare deoarece testul nu trebuie să depășească limita clasei. Ca rezultat, dezvoltatorul retrage conexiunea la baza de date și implementează această interfață folosind propriul obiect simulat . Acest lucru are ca rezultat un cod mai puțin coeziv, minimizând dependențele din sistem.

Când testarea unitară eșuează

Cod complex

Testarea software-ului este o sarcină combinatorie. De exemplu, fiecare valoare posibilă a unei variabile booleene ar necesita două teste, unul pentru TRUE și unul pentru FALSE. Ca rezultat, fiecare linie de cod sursă va necesita 3-5 linii de cod de testare.

Algoritmi precum Marching cubes sau arborele roșu-negru au un arbore de decizie ramificat și sunt necesare suite de teste uriașe pentru a verifica toate opțiunile: într-una dintre implementările arborelui roșu-negru din GitHub, au fost făcute douăsprezece teste pentru a verifica inserția [1] . În celălalt, ei construiesc automat 10! = 3,6 milioane de permutări și experimentați-le pe toate [2] .

Ca orice tehnologie de testare, testarea unitară nu vă permite să detectați toate erorile de program. Într-adevăr, aceasta rezultă din imposibilitatea practică de a urmări toate căile posibile de execuție a programului, cu excepția celor mai simple cazuri.

Rezultatul este cunoscut doar aproximativ

De exemplu, în modelarea matematică . Aplicațiile de afaceri funcționează adesea cu seturi finite și numărabile , în timp ce aplicațiile științifice funcționează cu seturi continue . [3] Prin urmare, este dificil de selectat teste pentru fiecare dintre ramurile programului, este dificil de spus dacă rezultatul este corect, dacă se menține acuratețea etc. Și, în multe cazuri, calitatea modelării este determinată „de ochi. ”, iar ultimul rezultat este înregistrat ca „referință”. Dacă se constată o discrepanță, noul rezultat este verificat manual și se stabilește care este mai bun: cel vechi sau cel nou.

Cod care interacționează cu sistemul

Codul care interacționează cu porturile , temporizatoarele , utilizatorul și alte părți „instabile” ale sistemului este extrem de dificil de testat într-un mediu izolat.

Dar asta nu înseamnă că testarea unitară este complet nepotrivită aici: forțează programatorul să treacă de la fișiere și porturi, de exemplu, la fluxuri abstracte . Acest lucru face ca codul să fie mai general (de exemplu, puteți trece de la fișiere la prize de rețea fără probleme ), mai testabil (puteți verifica situația „conexiune pierdută” scriind un flux care, după emiterea de N octeți, va simula un accident; verificați sub parte Windows din funcțiile de conversie a căii

Multithreading

Este practic o parte instabilă a sistemului. În plus, testele unitare sunt de obicei simple, în timp ce testele pentru sistemele multithreaded, dimpotrivă, ar trebui să fie destul de mari.

Erori de integrare și performanță

La efectuarea testelor unitare, fiecare dintre module este testat separat. Aceasta înseamnă că erorile de integrare, erorile la nivel de sistem, funcțiile executate în mai multe module nu vor fi detectate. În plus, această tehnologie este inutilă pentru testele de performanță. Astfel, testarea unitară este mai eficientă atunci când este utilizată în combinație cu alte tehnici de testare.

Cu o cultură generală scăzută a programării

Culegere de beneficiile testării unitare necesită respectarea strictă a tehnologiei de testare pe tot parcursul procesului de dezvoltare a software-ului. Este necesar să se păstreze nu numai înregistrări ale tuturor testelor efectuate, ci și ale tuturor modificărilor aduse codului sursă în toate modulele. În acest scop, ar trebui utilizat un sistem de control al versiunilor software . Astfel, dacă o versiune ulterioară a software-ului eșuează un test care a fost trecut cu succes înainte, va fi ușor să verificați variațiile codului sursă și să remediați eroarea. De asemenea, trebuie să vă asigurați că testele nereușite sunt urmărite și analizate în orice moment. Ignorarea acestei cerințe va duce la o avalanșă de rezultate ale testelor eșuate.

Probleme cu obiectele stub

Cu excepția celor mai simple cazuri, obiectul testat trebuie să interacționeze cu alte obiecte. Acești „colaboratori” - obiecte stub - sunt realizați extrem de simpli: fie extrem de simplificați (memorie în loc de bază de date), fie proiectați pentru un test specific și repetarea mecanică a sesiunii de schimb. Pot apărea probleme la schimbarea protocolului de schimb, caz în care obiectele stub trebuie să îndeplinească noile cerințe de protocol. [patru]

Dezvoltare de software încorporat

Este ușor să verificați dacă modulul funcționează pe mașina dezvoltatorului. Mai dificil - că pe mașina țintă, adesea foarte limitat [5] .

Unit Test Applications

Programare extremă

Programarea extremă presupune ca unul dintre postulate utilizarea instrumentelor automate de testare unitară. Acest set de instrumente poate fi creat fie de o terță parte (cum ar fi Boost.Test), fie de echipa de dezvoltare a aplicației.

Programarea extremă utilizează teste unitare pentru dezvoltarea bazată pe teste . Pentru a face acest lucru, dezvoltatorul, înainte de a scrie codul, scrie un test care reflectă cerințele pentru modul. Evident, testul înainte de scrierea codului nu ar trebui să funcționeze. Procesul ulterior se reduce la scrierea celui mai scurt cod care satisface acest test. După ce dezvoltatorul scrie următorul test, cod și așa mai departe de multe ori.

Tehnici de testare unitară

Complexitatea scrierii testelor unitare depinde de modul în care este organizat codul. O coeziune puternică sau o zonă mare de responsabilitate a entităților individuale (clase pentru limbaje orientate pe obiecte) poate face testarea dificilă. Stub-urile trebuie create pentru obiectele care comunică cu lumea exterioară (rețea, I/O fișier etc.). În terminologie, se disting stub-uri mai „avansate” - obiecte simulate care poartă logică. De asemenea, este mai ușor de testat prin separarea cât mai mult posibil din logică în funcții pure . Ele nu interacționează cu lumea exterioară în niciun fel și rezultatul lor depinde doar de parametrii de intrare.

Se obișnuiește să se separe codul de testare în directoare separate. Este de dorit ca adăugarea de noi teste la proiect să nu fie o sarcină dificilă și să fie posibilă rularea tuturor testelor. Unele sisteme de control al versiunilor, cum ar fi git, suportă cârlige ( English  hook ), cu care puteți configura lansarea tuturor testelor înainte de a efectua modificări. Dacă cel puțin unul dintre teste eșuează, modificările nu vor fi comise. De asemenea, pot fi aplicate sisteme de integrare continuă .

Trusa de instrumente

Există instrumente și biblioteci de testare unitară pentru cele mai populare limbaje de programare de nivel înalt. Unii dintre ei:

Suport la nivel de limbă

Unele limbi au suport pentru testarea unitară la nivel de sintaxă. Acest lucru elimină nevoia de a alege la ce cadru să se conecteze și facilitează portarea codului către alte proiecte.

Un exemplu de astfel de limbi:

Exemplu de cod în limbajul D

clasa ABC { this () { val = 2 ; } private int val ; public func () { val *= 2 ; } } unittest { ABC a ; a . func (); assert ( a . val > 0 && a . val < 555 ); // puteți accesa o variabilă privată în interiorul modulului }

Note

  1. GitHub - xieqing/red-black-tree: O implementare a arborelui roșu-negru în C. Preluat la 14 aprilie 2022. Arhivat din original la 14 aprilie 2022.
  2. http://orion.lcg.ufrj.br/java/bigjava/ch17/worked_example_2/RedBlackTreeTester.java
  3. De ce testele unitare nu funcționează în aplicații științifice / Habrahabr . Preluat la 9 iunie 2014. Arhivat din original la 14 iulie 2014.
  4. Problema dublării și învechirii cunoștințelor în obiecte simulate sau teste de integrare sunt bune / Habrahabr . Data accesului: 19 ianuarie 2016. Arhivat din original la 19 ianuarie 2016.
  5. Marek Kucharski Making Unit Testing Practical for Embedded Development Arhivat 25 mai 2022 la Wayback Machine

Vezi și

Literatură

  • Osherove, R. The Art Of Unit Testing Ediția a doua cu exemple în C#. - DMK Press, 2016. - ISBN 978-5-97060-415-1.

Link -uri

Site-uri și resurse Articole