Unelte open source pentru testarea unităților c

Arpan Sen. Director Tehnic, Synapti Computer Aided Design Pvt Ltd

Arpan Sen este un inginer de frunte care lucrează la dezvoltarea de software în domeniul automatizării de proiectare electronică. De câțiva ani a lucrat la unele funcții UNIX, inclusiv Solaris, SunOS, HP-UX și IRIX, precum și Linux și Microsoft Windows. El arată un interes deosebit față de tehnicile de optimizare a performanței software-ului, a teoriei grafurilor și a calculului paralel. Arpan este student absolvent în domeniul sistemelor software.

Ce este unitatea de testare?

Cu un grad ridicat de probabilitate, cod complex scris în C / C ++. conține erori. După ce este scris codul, găsirea acestor erori va fi, de asemenea, dificilă, cum ar fi găsirea unui ac în carul cu fan. O abordare mai rezonabilă este de a testa fragmente individuale de cod în momentul în care acestea sunt create. Pentru aceasta, sunt create teste mici (modulare) pentru a testa parametrii specifici, de exemplu, unele funcții în C. efectuând calcule intensive sau unele clase C ++. care necesită crearea unei structuri specifice de date, cum ar fi o coadă. Suita de test de regresie, creată în conformitate cu această filozofie, va include un set de teste unitare și un program de control care va executa aceste teste și va raporta rezultatele.

Crearea unui test pentru o anumită funcție sau clasă

Luați în considerare clasa de șir simplu afișată în Lista 1. Această clasă nu este foarte fiabilă, deci o vom testa cu Boost.

Listing 1. Clasa obișnuită de șir

Un număr de controale standard de testare, dacă șirul gol este lungime zero, în cazul în care ieșirea indicelui a frontierei au avut loc, care pot fi afișate în mesajele sau excepții de eroare, și așa mai departe .. În Listarea 2 arată unele dintre testele, ceea ce este important de a efectua orice implementare șir. Pentru a executa codul în Lista 2. compilați-l cu g ++ (sau orice alt compilator compatibil cu standardele C ++). Nu este necesară izolarea funcției principale, precum și utilizarea oricărei configurații de bibliotecă: toate definițiile necesare sunt incluse în antetul unit_test.hpp, care face parte din setarea Boost.

Lista 2. Teste unitare pentru o clasă de șir

Macrocomenzi BOOST_AUTO_TEST_SUITE BOOST_AUTO_TEST_SUITE_END și definesc începutul și sfârșitul pachetului de testare, respectiv. Testele individuale sunt localizate între aceste macrocomenzi și, în acest sens, semantica lor este similară cu spațiile de nume C ++. Fiecare test de unitate individuală este definit utilizând macrocomanda BOOST_AUTO_TEST_CASE. Listarea 3 arată rezultatele codului din listare 2.

Listing 3. Listing 2 output

Să examinăm mai atent procesul de creare a testelor unitare din listele anterioare. Ideea de bază este de a testa proprietățile individuale ale unei clase folosind macroul Boost. Macrocomenzi și BOOST_CHECK BOOST_REQUIRE_EQUAL sunt macro-uri predefinite (sau instrumente de testare), incluse în Boost cadru, și sunt destinate pentru a verifica dacă ieșirea codului.

Îmbunătățiți instrumentele de testare

Listing 4. Trei opțiuni pentru utilizarea instrumentelor de testare Boost

Primul test BOOST_CHECK a eșuat, precum și prima verificare BOOST_REQUIRE. Cu toate acestea, înainte de a doua verificare a BOOST_CHECK, cazul nu a ajuns, deoarece testul a fost întrerupt imediat după ce BOOST_REQUIRE a eșuat. Lista 5 arată rezultatele codului din listare 4.

Dacă trebuie să testați funcții individuale sau metode de clasă pentru a studia problema, cel mai simplu mod este să creați un nou test și să apelați procedura, trecând-o la argumentele de intrare și valorile așteptate. Lista 6 arată acest exemplu.

Listare 6. Folosind Boost pentru a testa funcțiile și metodele unei clase

Compararea eșantioanelor

Este comună compararea rezultatelor returnate de o funcție cu valoarea de referință. Pentru astfel de cazuri macro BOOST_CHECK este de asemenea foarte potrivit. În plus, utilizați clasa output_test_stream din biblioteca Boost. Clasa output_test_stream este inițializată folosind un fișier de referință (următorul exemplu este un fișier run.log). Ieșirea funcției C / C ++ este transmisă obiectului output_test_stream. și apoi se numește procedura match_pattern. Acest lucru este discutat în detaliu în Lista 7.

Listarea 7. Se potrivesc eșantioanele cu un fișier de referință

Compararea valorilor în virgulă mobilă

Unul dintre cele mai dificile controale din testele de regresie este compararea valorilor în virgulă mobilă. Uitați-vă la codul din Lista 8 - la prima vedere se pare că totul funcționează bine.

Listing 8. Compararea valorii în virgulă mobilă care nu funcționează

În timpul acestui test, macroul BOOST_CHECK se execută cu o eroare, în ciuda utilizării funcției sqrt. care face parte din biblioteca standard. Ce sa întâmplat? Problema comparării valorilor cu un punct de flotare este exact: valorile rezultatelor variabilelor f1 și rezultate * încep să difere, începând cu un punct zecimal. Pentru a remedia această situație, instrumentele de testare Boost includ macrocomenzile BOOST_WARN_CLOSE_FRACTION. BOOST_CHECK_CLOSE_FRACTION și BOOST_REQUIRE_CLOSE_FRACTION. Pentru a utiliza oricare dintre ele, trebuie să conectați un header predefinit Boost floating_point_comparison.hpp. Toate cele trei macrocomenzi au aceeași sintaxă, deci vom lua în considerare opțiunea de verificare (Listing 9).

Listing 9. BOOST_CHECK_CLOSE_FRACTION sintaxă macro

În loc să utilizați macrocomanda BOOST_CHECK. ca în Lista 9. încercați să utilizați macrocomanda BOOST_CHECK_CLOSE_FRACTION cu o precizie acceptabilă de 0,0001. Acest cod este afișat în listare 10.

Listing 10. Comparația valorii în virgulă mobilă care funcționează

Acest cod funcționează bine. Acum, să schimbăm acuratețea admisă în listare 10 la 0.0000001. Rezultatul este afișat în listare 11.

Afișare 11. Eroare de comparație din cauza limitei de acuratețe inacceptabile

O altă problemă comună (și destul de complexă), întâlnită în mod constant în versiunile de lucru ale aplicațiilor, este compararea variabilelor de tip double and float. Macro-ul BOOST_CHECK_CLOSE_FRACTION are o caracteristică remarcabilă care nu permite efectuarea unor astfel de comparații. Valorile din stânga și din dreapta ale macrocomenzii trebuie să fie de același tip: float sau dublu. Dacă în lista 12 variabila f1 este de tip double și rezultatul rezultat este un tip float, apare o eroare în timpul compilației.

Afișare 12. Eroare: argumentele din stânga și din dreapta BOOST_CHECK_CLOSE_FRACTION au diferite tipuri

Suport pentru predicate personalizate

Instrumentele de testare Boost pot funcționa cu condiții booleene. Puteți extinde aceste instrumente astfel încât acestea să susțină controale mai complexe, cum ar fi determinarea identității conținutului a două liste sau verificarea îndeplinirii unei anumite condiții pentru toate elementele vectorului. De asemenea, puteți extinde macroul BOOST_CHECK. oferind suport pentru predicate personalizate. Să încercăm să efectueze un audit special al conținutului listei generate de o funcție definită de utilizator al limbajului C. și de a determina dacă valorile tuturor elementelor care rezultă este mai mare decât 1. funcția de validare personalizată ar trebui să se întoarcă de tip boost :: test_tools :: predicate_result. Acest lucru este discutat în detaliu în Lista 13.

Listing 13. Verificarea predicatelor complexe cu ajutorul instrumentelor Boost

Obiectul predicate_result are un constructor implicit care are o valoare booleană. Aceasta explică de ce codul funcționează bine chiar și atunci când tipurile de revenire așteptate și reale ale validate_list sunt diferite.

O altă modalitate de a testa predicatele complexe cu Boost este utilizarea macrocomenzii BOOST_CHECK_PREDICATE. Avantajul acestei macrocomenzi este că nu utilizează predicate_result. Dezavantajul este o anumită complexitate a sintaxei. În macrocomanda BOOST_CHECK_PREDICATE, trebuie să treci numele și argumentul (sau argumentele) funcției. Lista 14 nu face același lucru cu lista 13. acesta folosește doar alte macrocomenzi. Rețineți că tipul de returnare validate_result este acum Boolean.

Lista 14. Macro BOOST_CHECK_PREDICATE

Plasați mai multe pachete de testare într-un singur fișier

Puteți pune mai multe pachete de testare într-un fișier. Fiecare pachet de testare trebuie să aibă o pereche de macrocomenzi BOOST_AUTO_TEST_SUITE. BOOST_AUTO_TEST_SUITE_END. definite în dosar. Lista 15 prezintă două pachete diferite de testare plasate într-un fișier. Când executați regresii, executați fișierul executabil utilizând opțiunea predefinită -log_level = test_suite. După cum puteți vedea din Lista 16. rezultatul generat folosind această opțiune este mai detaliat și rapid de depanat.

Listarea 15. Mai multe pachete de testare plasate într-un fișier

Mai jos este rezultatul rezultat din codul din Lista 15.

Afișarea 16. Executarea mai multor pachete de testare cu opțiunea -log_level

Înțelegerea structurii unei suite de testare

Până acum, am discutat despre pachetele de testare Boost care nu au o structură ierarhică. Acum vom încerca să creăm un pachet de testare cu Boost, care testează produsul software în modul în care îl văd de obicei un utilizator de instrumente externe. În interiorul cadrului de testare în sine există de obicei mai multe pachete de testare, fiecare dintre acestea verificând anumite funcții. De exemplu, cadrul de testare a regresiei pentru procesorul Word trebuie să conțină pachete de testare pentru a verifica suportul pentru fonturi, diferite formate de fișiere etc. Fiecare pachet de testare individual conține mai multe teste unitare. Lista 17 prezintă un exemplu de cadru de testare. Rețineți că punctul de intrare la care începe execuția codului este procedura numită (corect) init_unit_test_suite.

Listing 17. Crearea pachetului de test principal pentru efectuarea regresiilor

Fiecare pachet de testare (de exemplu pachetul ts1 din Lista 17) este creat folosind macrocomanda BOOST_TEST_SUITE. Macrocomanda așteaptă un șir care este numele pachetului de testare. Toate pachetele de testare sunt adăugate în final la pachetul principal de testare utilizând metoda de adăugare. De asemenea, creați un test folosind BOOST_TEST_CASE macro și adăugați-l la pachetul de testare folosind metoda add. De asemenea, puteți adăuga teste unitare la pachetul de test principal, deși acest lucru nu este recomandat. Metoda master_test_suite este definită ca parte a spațiului de nume impuls :: unit_test :: cadru - în ea pune în aplicare un Singleton. Codul din listare 18 (găsit în codul sursă al Boost-ului însuși) explică modul în care funcționează.

Listing 18. Înțelegerea metodei master_test_suite

Modulele de testare create folosind macrocomanda BOOST_TEST_CASE. luați ca argumente de intrare funcții pointeri. Prin urmare, în Lista 17, funcția test_case1. test_case2, etc. sunt funcții void goale pe care utilizatorul le poate programa așa cum dorește. Cu toate acestea, rețineți că setarea de testare Boost utilizează o anumită cantitate mică de memorie în heap; fiecare apel la BOOST_TEST_SUITE este redus la un apel nou pentru a stimula :: unit_test :: test_suite (<имя тестового пакета>).

Dispozitivul de testare este o stare preconfigurată a mediului în care se efectuează testul. La finalizarea testului, toate setările acestui mediu își iau valorile inițiale. Un exemplu de dispozitiv este prezentat în Lista 19.

Listarea 19. Amplificare simplă

Rezultatele sunt afișate în listare 20.

Listarea 20. Rezultatele utilizării programelor Boost

În loc să utilizați macrocomanda BOOST_AUTO_TEST_CASE, acest cod utilizează macroul BOOST_FIXTURE_TEST_CASE. în care este trecut un argument suplimentar. Metodele constructorului și distrugerii acestui obiect efectuează reglajul și curățarea necesare. Acest lucru confirmă o privire rapidă la antetul modulului Boost unit_test_suite.hpp (Lista 21).

Listing 21. Determinarea dispozitivului Boost în antetul unit_test_suite.hpp

Boost publică moștenește o clasă de la struct F (vezi Listing 19) și creează un obiect pe ea. În conformitate cu regulile de moștenire publică a C ++, toate variabilele protejate și publice ale clasei struct sunt accesibile direct din funcția ulterioară. Rețineți că variabila i, care este modificată în lista 19, aparține obiectului intern t cu tipul F (a se vedea Lista 20). Este destul de normal, dacă în pachetul de încercare de încercare de regresie este necesară inițializarea explicită (prin urmare, necesitatea utilizării dispozitivelor) doar pentru două sau trei teste. Lista 22 arată un pachet de testare în care numai unul dintre cele trei teste utilizează un dispozitiv de fixare.

Listarea 22. Pachetul Test Boost care conține teste cu corpuri de iluminat și fără corpuri de iluminat

Lista 22 conține elemente de fixare definite și utilizate într-un singur test. Utilizând macrocomanda BOOST_GLOBAL_FIXTURE (<имя фикстуры>) Boost permite, de asemenea, utilizatorilor să definească și să utilizeze corpurile globale. Puteți defini orice număr de planificări globale care vă permit să separați codul de inițializare. Un exemplu de utilizare a dispozitivelor globale este prezentat în Lista 23.

Listing 23. Utilizarea programelor globale pentru inițializarea regresiei

În cazul mai multor amenajări, amplasarea și distrugerea lor apar în ordinea în care au fost declarate. În lista 24, constructorul și distrugătorul clasei F sunt chemați înainte de constructor și distrugător de clasa F2, respectiv.

Afișarea 24. Folosirea mai multor elemente globale în regresie

Rețineți că nu puteți folosi corpurile globale ca obiecte pentru teste individuale. De asemenea, este imposibil să se obțină acces direct la metodele sau variabilele publice sau protejate non-statice în cadrul testului.

concluzie

  • Articol original Unelte de testare pentru unități C / C ++ cu sursă deschisă, Partea 1: Cunoașterea cadrului de testare a unității Boost.
  • Documentația Boost este un ghid exhaustiv pentru instrumentele de testare Boost
  • Politici și protocoale Boost (EN) - un ghid privind politicile și protocoalele de testare Boost
  • Lista de discuții Boost (EN) - diverse informații, inclusiv pașii de depanare în timpul instalării și testării

Articole similare