Codul de acoperire de la mit la realitate

A existat o perioadă în care programatorii au fost plătiți de numărul de linii de cod pe care le-au scris. Ei au fost tratați ca mașini producătoare de coduri sursă care lucrau în cabine și, în schimb, au considerat programarea doar un loc de muncă pe care îl fac opt ore pe zi și apoi uită de asta, pentru restul zilei.

Dar vremurile s-au schimbat. Cele mai multe locuri de muncă cubice au dispărut, iar programatorii au început să-și iubească meseria. Odată cu apariția tehnicilor Agile și a mișcării software de meserii, au apărut multe instrumente noi pentru a ajuta programatorul și procesul. TDD devine lent modul de facto de scriere a codului, iar secretele lui SCRUM sau Kanban au fost dezvăluite chiar și programatorilor din cele mai întunecate colțuri ale lumii cabinelor.

Testarea automată și dezvoltarea bazată pe teste (TDD) reprezintă unele dintre tehnicile esențiale pe care Agile le-a furnizat programatorilor noștri. Și un instrument care vine cu aceste metodologii este folosit pentru a produce acoperire cod de testare, care este subiectul acestui articol.

Definiție

"În domeniul informaticii, acoperirea codului este o măsură folosită pentru a descrie gradul în care codul sursă al unui program este testat de o anumită suită de testare". ~ Wikipedia

Definiția de mai sus, luată din Wikipedia, este una dintre cele mai simple modalități de a descrie ce acoperire de cod înseamnă. Practic, în proiectul dvs. aveți o grămadă de cod de producție, precum și o grămadă de cod de testare. Codul de testare exercită codul de producție, iar acoperirea de testare vă arată cât de mult din codul de producție a fost efectuat de teste.

Informațiile pot fi prezentate în mai multe moduri, de la procente simple la grafică frumoasă sau chiar în evidențierea în timp real în IDE-ul favorit.

Să o verificăm în acțiune

Vom folosi PHP ca limbă pentru a exemplifica codul nostru. În plus, vom avea nevoie de PHPUnit și XDebug pentru a testa codul nostru și pentru a aduna datele de acoperire.

Codul sursă

Aici este codul sursă pe care îl vom folosi. Puteți găsi, de asemenea, în arhiva atașată.

(str string ($ string)> $ cols) $ lastSpaceIndex = strrpos (substr ($ string, 0, $)) cols) "); dacă $ lastSpaceIndex! == false && substr ($ string, $ cols, 1)! = ") retur substr ($ string, 0, $ lastSpaceIndex) string ($ strings, $ cols), $ cols); else return substr ($ string, 0, $ cols)  return $ string;

Codul de mai sus conține o funcție simplă care înfășoară textul într-un număr specificat de caractere, pe linie.

Codul de testare

Am scris acest cod folosind Test Driven Development (TDD) și avem o acoperire de cod 100% pentru acesta. Acest lucru înseamnă că, prin rularea testului nostru, exersăm fiecare linie a codului sursă.

requ_once __DIR__. '/ ... / WordWrap.php'; clasa WordWrapTest extinde PHPUnit_Framework_TestCase function testItCanWrap () $ w = new WordWrap (); $ this-> assertEquals (", $ w-> wrap (null, 0)); $ this-> assertEquals (", $ w-> wrap (" $ w-> wrap ('a', 1)); $ this-> assertEquals ("a \ nb", $ w-> nc ", $ w-> wrap ('a bc d', 3)); $ this-> assertEquals (" a \ nbc \ nd ";

Executarea testelor în CLI cu acoperire numai cu text

O modalitate de a obține date de acoperire este de a rula testele noastre în CLI (interfața liniei de comandă) și de a analiza rezultatele. Pentru acest exemplu, vom presupune un sistem de operare similar cu UNIX (Linux, MacOS, FreeBSD, etc). Utilizatorii de Windows vor trebui să adapteze ușor căile și numele executabile, dar ar trebui să fie destul de asemănătoare.

Să deschidem o consolă și să schimbăm directoarele către dvs. Test pliant. Atunci fugi PHPUnit cu opțiunea de a genera date de acoperire ca text simplu.

phpunit -coverage-text =. / cover.txt ./WordWrapTest.php

Acest lucru ar trebui să funcționeze din cutia de pe majoritatea sistemelor dacă XDebug este instalat, dar în unele cazuri, este posibil să întâlniți o eroare legată de fusurile orare.

Avertisment PHP: data (): Nu este sigur să vă bazați pe setările zonei de oră a sistemului. Sunteți * necesar * pentru a utiliza setarea date.timezone sau funcția date_default_timezone_set (). În cazul în care ați utilizat oricare dintre aceste metode și dacă primiți în continuare acest avertisment, cel mai probabil ați introdus greșit codul de identificare al zonei de fus orar. Am selectat fusul orar "UTC" pentru moment, dar vă rugăm să setați data.timezone pentru a selecta fusul orar. în phar: ///usr/share/php/phpunit/phpunit.phar/ PHP_CodeCoverage-1.2.10 / PHP / CodeCoverage / Raport / Text.php pe linia 124 

Acest lucru poate fi rezolvat cu ușurință prin specificarea setării sugerate în aplicația dvs. php.ini fişier. Puteți găsi modalitatea de a specifica fusul orar în această listă. Sunt din România, deci voi folosi următoarea setare:

date.timezone = Europa / București

Acum, dacă alergi PHPUnit comanda din nou, nu ar trebui să vedeți mesaje de eroare. În schimb, rezultatele testului vor fi afișate.

PHPUnit 3.7.20 de Sebastian Bergmann ... Timp: 0 secunde, Memorie: 5.00Mb OK (2 teste, 7 afirmații) 

Datele de acoperire vor fi în fișierul text specificat.

$ cat ./coverage.txt Raport de acoperire a codului 2014-03-02 13:48:11 Rezumat: Clase: 100.00% (1/1) Metode: 100.00% (1/1) Linii: 2.68% (14/522) WordWrap Metode: 100,00% (1/1) Linii: 100,00% (7/7) 

Să analizăm puțin acest lucru.

  • Clase: se referă la câte clase au fost testate și câte dintre ele au fost acoperite. WordWrap este singura noastră clasă.
  • metode: la fel ca la clase. Avem doar noi înfășurați () metodă, nimic altceva.
  • Linii: aceeași ca mai sus, dar pentru linii de cod. Aici avem o mulțime de linii, deoarece rezumatul conține toate liniile de la PHPUnit în sine.
  • Apoi avem o secțiune pentru fiecare clasă. În cazul nostru, asta e numai WordWrap. Fiecare secțiune are propriile sale metode și detalii de linie.

Pe baza acestor observații, putem concluziona că codul nostru este 100% acoperit de teste. Exact cum ne-am așteptat înainte de analizarea datelor de acoperire.

Generarea rezultatului de acoperire HTML

Doar modificând un parametru simplu pentru PHPUnit, putem genera o ieșire HTML plăcută.

$ mkdir ./coverage $ phpunit --coverage-html ./coverage ./WordWrapTest.php 

Dacă vă verificați ./ acoperire director, veți găsi o mulțime de fișiere acolo. Nu voi lipi lista aici pentru că este destul de extinsă. În schimb, vă voi arăta cum arată într-un browser web.

Acesta este echivalentul secțiunii sumare din versiunea textului de mai sus. Putem mări prin urmărirea link-urilor propuse și pentru a vedea mai multe detalii.

Acoperire în interiorul IDE-ului nostru

Exemplele anterioare au fost interesante și sunt destul de utile, dacă codul dvs. este construit pe un server la distanță la care aveți acces numai la SHH sau la web. Dar nu ar fi frumos să ai toate aceste informații, să trăiești în IDE-ul tău?

Dacă utilizați PHPStorm, totul se află la o distanță de un singur clic! Selectați pentru a rula testele cu acoperire și toate informațiile se vor afișa pur și simplu, în mod magic.

Informațiile despre acoperire vor fi prezente în IDE, în mai multe moduri și în mai multe locuri:

  1. Procentajul de acoperire a testului va fi afișat în apropierea fiecărui director și fișier.
  2. În editor, în timp ce modificați codul, în partea stângă a numerelor de linie, un dreptunghi verde sau roșu va marca fiecare linie. Verde reprezintă liniile testate, iar roșu reprezintă cele netestate. Liniile fără cod actual (linii goale, numai bretele sau paranteze, declarații de clasă sau metodă) nu vor avea niciun semn.
  3. În partea dreaptă vor fi browsere de fișiere în care puteți răsfoi și sorta rapid fișierele după acoperire.
  4. În ieșirea de test, veți vedea o linie de text care vă anunță că a fost generată o acoperire a codului.

Miturile despre acoperirea codului

Cu o unealtă atât de puternică în mâinile dezvoltatorului și sub nasul conducerii, era inevitabil ca unele mituri să pară. După ce programatorii au refuzat să fie plătiți de numărul de linii de cod pe care le scriu sau managerii și-au dat seama cât de ușor este sistemul de joc, unii dintre ei au început să plătească programatorii cu procentul de acoperire a codului. Acoperirea de cod mai mare înseamnă că programatorul a fost mai atent, nu? E un mit. Acoperirea codului nu reprezintă o măsură a cât de bine scrieți codul.

Uneori, programatorii tind să creadă că codul cu acoperire de 100% nu are bug-uri. Un alt mit. Acoperirea cu coduri vă spune doar că ați testat fiecare linie de cod. Este o măsură a numărului de linii exercitate. Nu este o măsură a numărului de linii implementate corect. De exemplu, algoritmi pe jumătate scrise cu doar teste jumătate definite vor avea în continuare o acoperire de 100%. Acest lucru nu înseamnă că algoritmul este terminat sau că funcționează corect.

În cele din urmă, gamingul sistemului este foarte ușor. Desigur, dacă utilizați TDD, aveți în mod natural o valoare de acoperire ridicată. Pe proiecte întregi, 100% este imposibil. Dar pe module sau clase mici, obținerea unei acoperire de 100% este foarte ușoară. Luați, de exemplu, codul sursă și imaginați-vă că nu aveți niciun test. Care ar fi cel mai simplu test pentru a exersa tot codul?

funcția testItCanWrap () $ w = WordWrap nou (); $ this-> assertEquals ("a b \ nc", $ w-> wrap ('a b c', 3)); $ this-> assertEquals ("a \ nbc \ nd", $ w-> wrap ('a bc d', 3)); 

Asta e. Două afirmații și acoperire completă. Nu asta ne dorim. Acest test este atât de departe de a fi descriptiv și complet, încât este ridicol.

Realitatea despre acoperirea codului

Acoperirea codului este un indicator de stare, nu o unitate pentru a măsura performanța sau corectitudinea.

Acoperirea codului este pentru programatori, nu pentru manageri. Este o modalitate de a observa probleme în codul nostru. O modalitate de a găsi clase vechi, netestate. O modalitate de a găsi căi care nu sunt exercitate de teste care ar putea duce la probleme.

Pe proiectele reale, acoperirea codului va fi întotdeauna sub 100%. Atingerea unei acoperire perfectă nu este posibilă sau, dacă este, este rareori o necesitate. Cu toate acestea, pentru a avea o acoperire de 98%, trebuie să vizați 100%. Având altceva ca ținta dvs. este non-sens.

Aici este acoperirea codului aplicației de configurare StorageOS a Syneto.

Totalul este de aproximativ 35%, dar rezultatele au nevoie de interpretare. Majoritatea modulelor sunt în verde, cu o acoperire de peste 70%. Cu toate acestea, există un singur director, Vmware, care scade în medie. Este un modul cu multe clase care conțin numai definiții pentru API-ul de comunicare. Nu există niciun motiv pentru a testa aceste clase. Acestea au fost generate automat de codul de încredere. Programatorii vor ști asta și vor ști cum să interpreteze rezultatele. Un manager poate insista să-l testeze, deoarece este un bar roșu și arată suspicios pentru cineva care nu cunoaște detaliile interne ale proiectului. Ar avea sens să o testezi? Deloc! Ar fi un test inutil, care ar lua zeci de sute de secunde de timp de construcție fără nici un avantaj.

Gândurile finale

Deci aici este locul unde suntem cu codul de acoperire: este un instrument excelent pentru programatori, o sursă de informații pentru a evidenția posibilele probleme, o realitate greșită pentru majoritatea managerilor și un alt instrument pentru a forța și măsura activitățile programatorilor. Ca și în cazul oricărui alt instrument, acesta poate fi folosit corect și folosit cu ușurință. 

Cod