Sunteți pe pagina 1din 15

Test Driven Development

Alexandru Angelescu
Facultatea de Informatică, Universitatea “Al. I. Cuza” Iași, România
alexandru.angelescu@info.uaic.ro

Abstract
Test Driven Development (TDD) reprezintă o practică în dezvoltarea de software în care cazurile de
test pentru unități sunt scrise prin incrementare înaintea implementării codului. În cadrul studiului de
cercetare coordonat de George și Williams [13], a fost organizat un set de experimente structurate cu
24 de programatori profesioniști ce lucrează în sistem pair-programming. Un grup a dezvoltat cod
folosind TDD, în timp ce al doilea grup a utilizat o abordare de tip cascadă. Ambele grupuri au
dezvoltat un mic program Java. S-a descoperit că dezvoltatorii TDD au produs un cod de o calitate
superioară, care a trecut cu 18% mai multe cazuri de test funcționale de tip black box. Însă,
dezvoltatorii TDD au necesitat cu 16% mai mult timp pentru dezvoltare. Prin analiză s-a stabilit o
corelație rezonabilă între timpul necesar și calitatea rezultată. O ipoteză susține că acea calitate
înaltă a codului scris folosind practica TDD se datorează granularității metodologiei, care ar putea
încuraja o verificare și o validare mai frecvente și mai strânse. În ultimul rând, programatorii ce au
urmat procesul de tip cascadă, de multe ori, nu au creat cazurile de testare automată cerute după
finalizarea codului lor, fapt ce ar putea să indice o tendință în cadrul practicienilor către o testare
inadecvată. Această observație sprijină teoria că TDD posedă potențialul de a crește nivelul de
testare în industrie, sub formă de testare ca parte integrantă a dezvoltării de cod.

Cuvinte cheie

Test Driven Development, Extreme Programming, metodologii agile, inginerie software.

1. Introducere
Metodologia Test Driven Development (TDD) reprezintă elementul principal al abordării Agile de
dezvoltare de cod derivate din Extreme Programming (XP) [1] și din principiile din Agile Manifesto [2].
TDD este cunoscută şi sub alte denumiri, precum Test First Design (TFD), Test First Programming
(TFP) şi Test Driven Design (TDD). Potrivit literaturii de specialitate, practica TDD nu este chiar atât de
nouă, fiind folosită sporadic timp de decenii [11]; o referință timpurie legată de utilizarea TDD este
proiectul Mercury al NASA din anii ’60 [3]. Cercetările în domeniu afirmă că diferite efecte pozitive
pot fi obținute prin utilizarea TDD. Această abordare ar conduce la garantarea posibilității de testare
și la obținerea unui grad foarte ridicat de acoperire a codului [4], la creșterea încrederii
dezvoltatorului [5], la ușurarea producerii unor sisteme cu un grad mare de coeziune și cu un cuplaj
redus și la existența unui număr mai mare de integrări care ar permite echipelor mai mari de
programatori să lucreze pe aceeași bază de cod, deoarece codul ar putea fi introdus în sistemul de
versiuni mai des. Practica TDD ar încuraja de asemenea o claritate mai bună privind sfera

1
implementării, ajutând la separarea design-ul logic de cel fizic și la simplificarea design-ului, prin
implementarea codului strict necesar la un moment dat [6].

Obiectul este elementul principal de construcție în Programarea Orientată Obiect (POO). Dacă
obiectele nu sunt create judicios pot apărea probleme de dependințe, precum cuplarea strânsă între
obiecte și super clase fragile (incapsulare inadecvată). Aceste probleme ar putea rezulta într-o bază
de cod complexă de mari dimensiuni care se compilează și rulează încet. Creatorul metodologiei XP,
Kent Beck afirma: “Codul având testele la început are tendința să fie mai coeziv și mai puțin cuplat
decât codul în care testarea nu este o parte a ciclului intim de programare.” [6] Susținătorii TDD
argumentează că acest cuplaj redus are loc deoarece practica conduce spre construirea de obiecte cu
adevărat necesare (pentru a trece cazurile de test bazate pe cerințe) spre deosebire de construirea
de obiecte care sunt presupuse a fi necesare (din cauza unei posibile înțelegeri improprii a
cerințelor). O regulă importantă din TDD este: “Dacă nu poți să scrii un test pentru codul pe care
urmează să-l scrii, atunci nici nu ar trebui să te gândești la scrierea codului.” [12]. Mai mult, TDD
permite testarea continuă în regresie care îmbunătățește calitatea codului [5].

În ciuda caracterului inovator, unii dezvoltatori de software ar putea fi îngrijorați de lipsa unui design
inițial în TDD și de nevoia de a lua decizii de design la fiecare etapă din dezvoltare. De aici apare
nevoia de a analiza empiric și de a cuantifica eficiența acestei practici.

Lucrarea lui George și Williams [13] examinează empiric două ipoteze:

1. Practica TDD va genera cod cu o calitate superioară pentru codul extern atunci când este
comparat cu cel dezvoltat printr-o practica mai tradițională precum cea de tip cascadă.
Calitatea codului extern este evaluată pe baza numărului de cazuri de test funcționale (cazuri
de test de tip black box) trecute.
2. Programatorii care utilizează TDD vor dezvolta cod mai rapid decât cei care dezvoltă cod cu
ajutorul unei metodologii mai tradiționale de tip cascadă. Viteza programatorilor este
măsurată prin timpul necesar (în ore) pentru a finaliza un program specificat.

Pentru a investiga aceste ipoteze, datele pentru cercetare au fost colectate de la trei seturi de
experimente structurate îndeplinite de dezvoltatori profesioniști.

2. Test Driven Development


În ciuda numelui, TDD nu este o tehnică de testare, ci mai mult o tehnică de dezvoltare și design în
care testele sunt create înaintea codului de producție [6]. Testele sunt adăugate în mod gradual pe
parcursul procesului de implementare, iar atunci când testul este trecut cu succes, codul trece printr-
o fază de refactoring pentru a îmbunătăți structura sa internă. Acest ciclu prin incrementare este
repetat până când toate funcționalitățile sunt implementate [4]. Ciclul TDD constă în șase pași
fundamentali [7]:

1. Scrierea unui test pentru o parte a funcționalității,


2. rularea tuturor testelor pentru a vedea noul test eșuând,
3. scrierea codului care trece cu succes testele,
4. rularea testelor pentru a le trece pe toate cu succes,
5. trecerea codului printr-un proces de refactoring și

2
6. rularea tuturor testelor pentru a vedea dacă procesul de refactoring a modificat
comportamentul extern.

Primul pas implică doar scrierea unei porțiuni de cod care testează funcționalitatea dorită. Al doilea
este necesar pentru a valida testul, adică testul nu trebuie trecut cu succes în acest moment,
deoarece comportamentul aflat în implementare înca nu trebuie să existe. Cu toate acestea, dacă
testul este trecut cu succes, atunci el nu testează comportamentul corect sau principiile TDD nu au
fost respectate. Al treilea pas este scrierea codului. Trebuie avută în vedere, însă, cerința de a scrie
(într-o manieră de tip greedy) cât mai puțin cod necesar doar pentru a trece cu succes testul [4].
Apoi, toate testele trebuie rulate pentru a vedea dacă modificarea nu a introdus vreo problemă în
altă parte a sistemului. Odată ce toate testele au fost trecute cu succes, structura internă a codului ar
trebui îmbunătățită prin refactoring.

Munca este menținută sub controlul intelectual al dezvoltatorului deoarece el sau ea ia în


permanență mici decizii de design sau de implementare și mărește funcționalitatea într-un ritm
relativ consistent. O nouă funcționalitate nu este considerată a fi implementată corespunzător decât
în cazul în care aceste cazuri noi de test și toate celelalte cazuri pentru unit testing scrise anterior
pentru codul existent se execută corect. Ciclul descris este prezentat în Figura 1 ([7], adaptare din [8],
[5], [9]).

Figura 1. Ciclul TDD

3
2.1. Scrierea testelor
Testele în TDD se numesc teste de programator. Ele se aseamănă cu unit tests cu deosebirea că sunt
scrise pentru comportamente și nu pentru metode [4]. Este important ca testele să fie scrise pentru a
fi independente ca ordine, adică rezultatul să rămână identic indiferent de secvența în care testele
sunt executate [5].

Testele sunt grupate în diferite suite pe baza comportamentelor pe care le testează. Astfel se poate
testa o anumită parte a sistemului fără să fie necesară rularea tuturor testelor. O metodă de test este
cea mai mică unitate și ar trebui să testeze un singur comportament, în timp ce un caz de test adună
împreună teste înrudite. O concepție greșită comună este că un caz de test ar trebui să conțină toate
testele unei anumite clase. Această înțelegere greșită este consolidată de majoritatea plugin-urilor
pentru IDE-uri, pentru că ele generează, de obicei, pentru fiecare clasă un caz de test care conține
metode de test pentru fiecare metodă. Reutilizarea dependințelor este permisă prin aplicarea de
precondiții și presupuneri identice cu fiecare metodă de test prin metodele setup() și teardown() în
fiecare caz de test. Astfel, testele devin repetabile și pot fi rulate identic în același context de
execuție de fiecare dată. [4]

În scrierea testelor trebuie avut în vedere faptul că testele ar trebui concentrate pe testarea
adevăratelor comportamente, adică, dacă un sistem trebuie să manevreze input-uri multiple, testele
ar trebui să reflecte input-uri multiple. Este la fel de importantă trecerea testelor printr-un proces de
refactoring în timpul ciclului de dezvoltare, în sensul că nu ar trebui să existe o listă de 10 date de
intrare dacă o listă de 3 date de intrare ar conduce la aceleași decizii de design și implementare. [5]

2.2. Execuția testelor


Testele automate ar trebui executate după fiecare modificare adusă codului aplicației pentru a crea
siguranța că schimbările nu au introdus erori în versiunea anterioară a codului [4]. Execuția testelor
este de obicei realizată cu ajutorul unor instrumente de unit testing, precum JUnit, un framework
simplu pentru scrierea de teste repetabile în Java. În ciclul TDD, testul trebuie rulat după scrierea
testului, scrierea codului și după procesul de refactoring.

2.3. Scrierea codului


În practica TDD, scrierea codului este în realitate un proces ce are ca scop funcționarea corectă a
testelor, adică scrierea codului care trece cu succes de teste. Beck propune trei abordări diferite
pentru aceasta: “falsificarea”, triangularea și implementarea în clar. Primele două sunt tehnici mai
puțin utilizate în munca concretă de dezvoltare. Cu toate acestea, ele pot fi folositoare pentru
implementarea unor porțiuni mai mici a unor soluții mai mari și mai complexe, atunci când
dezvoltatorul nu are o vedere clară asupra modului de implementare sau abstractizare a sistemului
[5].

“Falsificarea” poate fi utilizată, de exemplu, prin înlocuirea valorii returnate de o anumită metodă cu
o constantă. Este oferită astfel o cale rapidă de a depăși cu succes un test. Există un efect psihologic
deoarece îi conferă programatorului încrederea să treacă mai departe la refactoring și administrează

4
și controlul sferei de influență începând cu un exemplu concret și generalizând pornind din acel
punct. Implementarea abstractă este antrenată prin perceperea duplicării între test și cod [5].
Implementarea “falsificată” poate oferi un punct de plecare către soluția corectă dacă programatorul
nu știe într-adevăr de unde să înceapă să scrie codul.

Tehnica triangulării poate fi folosită pentru a ajunge la abstractizarea corectă a comportamentului,


atunci când soluția “falsificată” nu mai poate fi utilizată în continuare. De exemplu, există cel puțin
două cazuri diferite în metoda de test necesitând valori returnate diferite și, evident, returnarea unei
constante nu le satisface pe amândouă. După obținerea unei implementări abstracte, cealaltă
presupunere devine redundantă cu prima și ar trebui eliminată [5].

Implementarea în clar este utilizată atunci când programatorul este încrezător și știe cu siguranță
cum să implementeze un anumit proces. Punerea în aplicare în mod constant a implementării în clar
poate fi epuizantă din moment ce necesită întotdeauna perfecțiune. În momentul în care testele
încep să eșueze consecutiv, este recomandabilă utilizarea “falsificării” sau a “triangulării” până când
revine încrederea în forțele proprii [5].

2.4. Refactoring
Procesul de refactoring îmbunătățește structura internă prin editarea codului funcțional existent,
fără a modifica comportamentul său extern [4]. Este esențial, deoarece integritatea design-ului
software-ului se destramă în timp din cauza presiunii acumulate prin modificări, adăugiri și corectări
de bug-uri [10]. În practica TDD, este folosit pentru a face ordine în cod după ce s-au realizat cele mai
simple acțiuni pentru a trece cu succes de test. Procesul de refactoring asupra codului de test este la
fel de important ca și procesul de refactoring asupra codului aplicației [4].

Ideea din spatele fazei de refactoring este de a realiza modificările sub forma unei serii de pași mici
fără a introduce noi defecte în cadrul sistemului. Procesul de refactoring necesită o suită puternică de
teste automate deoarece este de obicei efectuat manual și comportamentul extern al codului poate
fi modificat neintenționat în timpul acelui proces din cauza factorului uman [10].

3. Avantaje și limitări
Există numeroase avantaje în a scrie cazurile de test înaintea codului de producție, TDD putând fi
considerată superioară altor abordări:

 În orice proces, există o discrepanţă între decizie (design-ul dezvoltat) şi feedback


(performanţa obţinută prin implementarea acelui design). Succesul metodologiei TDD poate
fi atribuit diminuării, sau chiar a eliminării acelei discrepanţe, din moment ce ciclul granular
testează-apoi-programează oferă în mod constant feedback dezvoltatorului [5]. Drept
rezultat, defectele şi cauzele defectelor pot fi uşor identificate – defectul trebuie să se
regăsească în codul care tocmai a fost scris sau în codul cu care porţiunea de cod adăugată
recent interacţionează. Un principiu de bază al Ingineriei Software des citat împreună cu
Preţul Schimbării [15], este următorul: cu cât defectul rămâne mai mult timp într-un sistem
software cu atât mai dificil şi mai costisitor este de îndepărtat. Timpul necesar rezolvării

5
defectelor este semnificativ mai mic decât metodologia tradițională de tip cascadă în care
codul este testat după zile sau săptămâni de la implementare, iar dezvoltatorul trebuie să
treacă mai departe la alte module. De aceea, această granularitate mai ridicată a TDD-ului
diferenţiază această practică de alte modele de testare şi dezvoltare.
 Practica TDD convinge programatorii să scrie cod care este testabil în mod automat, având
funcţii/metode ce returnează o valoare ce poate fi verificată cu rezultatele aşteptate.
Beneficiile testării automate includ: (1) producerea unui sistem sigur, (2) îmbunătăţirea
calităţii efortului de testare şi (3) reducerea efortului de testare şi minimizarea programului
de lucru [14].
 Implementarea are șanse mai mari să se potrivească cu cerințele originale definite de
management-ul pentru produs. Cazurile de test sunt generate ușor din cazurile de utilizare
sau din scenariile pentru user și reflectă cu acuratețe specificațiile funcționale fără
interferențe din partea constrângerilor și limitărilor design-ului arhitecturii și construcțiilor de
programare. Abordarea garantează până la un anumit punct că versiunea finală va satisface
cerințele clientului sau ale management-ului pentru produs.
 Metodologia previne ca un design sau unele componente nejustificate să creeze probleme în
cadrul produsului. Cazurile de test sau driver-ele de unit testing definesc setul exact de
funcționalități cerute. Este destul de ușor de identificat codul redundant, de detectat și
eliminat sarcinile tehnologice inutile.
 Cazurile de test TDD crează o bază de testare prin regresie. Prin rularea continuă a acestor
cazuri de test automate, este uşor de determinat dacă o modificare nouă provoacă probleme
în sistemul existent. Această bază de testare va permite de asemenea o integrare uşoară a
noilor funcţionalităţi în baza de cod existent.
 Existența în prealabil a cazurilor de test permite dezvoltatorului să ofere o primă variantă a
unei implementări pentru scopurile de prototipizare, evaluare sau alpha release și să amâne
o implementare mai formală prin refactoring.
 TDD se încadrează convenabil în procese agile centrate pe client precum SCRUM. De
exemplu, faza de sprint poate fi definită ca implementarea funcționalității pentru a fi
executată relativ la un set pre-definit de cazuri de test în locul unui set mai tradițional de
specificații sau enunțuri de problemă.
 TDD poate conduce spre un cod mai modularizat, mai flexibil și mai extensibil. Metodologia
necesită ca dezvoltatorul să privească software-ul ca pe unități mici ce pot fi scrise și testate
independent și integrate împreună ulterior.

La fel cu orice altă metodologie de dezvoltare de software, TDD posedă unele limitări clare:

 Se îmbină foarte bine cu instrumentele de unit testing, dar nu poate fi scalată pentru
dezvoltarea de GUI-uri web-based sau lucrul cu baze de date, cu toate că se pot crea ușor
clienți SQL, ODBC sau JDBC sau clienți HTTP.
 Metodologia este greoaie dacă design-ul, limbajul de programare sau IDE-ul nu posedă un
unit test framework integrat precum C++test sau JUnit.

6
4. Studii de cercetare privind TDD
Recent, cercetătorii au început să organizeze studii asupre eficacităţii practicii TDD. Muller şi Hagner
[16] au coordonat un experiment structurat pentru a compara TDD cu programarea tradiţională.
Experimentul, organizat împreună cu 19 studenţi absolvenţi, a măsurat eficacitatea practicii TDD în
ceea ce priveşte (1) timpul de dezvoltare, (2) calitatea codului rezultat şi (3) inteligibilitatea.
Cercetătorii au împărţit participanţii la experiment în două grupuri, cel pentru TDD şi cel de control,
fiecare grup rezolvând aceeaşi sarcină. Sarcina era de a finaliza un program în care specificaţiile erau
oferite împreună cu design-ul necesar şi declaraţiile metodelor; studenţii au completat conţinutul
pentru metodele cerute. Cercetătorii au organizat programarea în această manieră pentru a facilita
testarea pentru acceptarea automată în analiza lor.

Grupul TDD a scris cazurile de test pe măsura ce codul era creat, în maniera descrisă anterior;
studenţii din grupul de control au formulat cazurile de test automate după finalizarea codului.
Experimentul s-a desfăşurat în două faze, o fază de implementare (FI) urmată de o fază de testare
pentru acceptare (FA). După FI, studenţii au fost înştiinţaţi asupra cazurilor de test pentru acceptare
pe care nu le-au trecut cu succes; apoi li s-a oferit ocazia de a-şi corecta codul. Cercetătorii nu au
descoperit nici o diferenţă între grupuri în ceea ce priveşte timpul total pentru dezvoltare. Grupul
TDD a avut un grad de fiabilitate mai redus după faza de implementare şi un grad de fiabilitate mai
mare după faza FA. Însă, grupul TDD a avut un număr de erori semnificativ mai mic din punct de
vedere statistic la reutilizarea codului. Pe baza acestor rezultate cercetătorii au concluzionat că
scrierea de cod în manieră testele-la-început nu conduce la o dezvoltare mai rapidă şi nici nu oferă o
creştere în calitate. Gradul de înţelegere a programului este însă mai mare, măsurat din punctul de
vedere al reutilizării corecte a interfeţelor existente.

Aceste rezultate experimentale trebuie luate în considerare în contextul limitărilor lor: dimensiunea
eşantionului a fost redusă, studenţii aveau o experienţă limitată cu practica TDD şi rezultatele au fost
estompate într-o anume masură de dispersia mare a datelor. În plus, corectitudinea externă a
rezultatelor lor poate fi îmbunătăţită prin coordonarea altor studii cu participarea unor programatori
profesionişti.

5. Abordarea muncii de cercetare


George si Williams [13] au organizat trei studii experimentale pentru TDD [17] împreună cu
programatori profesionişti. Aceste rezultate pot fi adăugate la cele prezentate anterior.

5.1. Detalii despre experiment


Au fost coordonate sedinţe experimentale cu grupuri de opt dezvoltatori în cadrul a trei companii
(John Deere, RoleModel Software şi Ericsson). În fiecare şedinţă experimentală, dezvoltatorii au fost
desemnaţi aleator să lucreze în perechi într-unul din două grupuri: grupul TDD şi grupul de control.
Toţi dezvoltatorii au utilizat practica pair-programming (în care doi programatori dezvoltă software
împreună la un singur computer) [18]. Fiecare pereche a fost rugată să dezvolte o aplicaţie de tip joc
de bowling (adaptată dintr-un episod XP [19]). Perechile din grupul de control au folosit abordarea
convenţională design-dezvoltare-testare-debugging (modelul cascadă) [20]. Toţi participanţii la

7
experiment au fost rugaţi să dezvolte un mic program în concordanţă cu un set de cerinţe.
Participanţii au fost rugaţi să înmâneze programele lor la terminarea activităţilor în maniera descrisă.
Apoi, proiectele lor au fost evaluate.

Cercetătorii s-au aşteptat ca programatorii profesionişti să scrie un cod care să trateze toate
condiţiile pentru erori într-un mod graţios. Însă, după analizarea rezultatelor primei runde, s-a
descoperit o situaţie diferită. Ei au descoperit că majoritatea echipelor iniţiale au stabilit că
implementarea lor este completă atunci când au putut să treacă cu succes cazurile de test pentru
acceptare specificate de cercetători. Din acest motiv, în următoarele două runde, li s-a cerut în mod
clar tuturor dezvoltatorilor să trateze toate condiţiile pentru erori graţios şi nici una dintre perechi nu
a primit cazuri de test pentru acceptare. În plus, în următoarele runde de experiment, dezvoltatorii
din grupul de control au fost rugaţi să scrie cazuri de test automate după etapa de dezvoltare. Mai
mult, nivelul de experienţă privind metodologia TDD a celor 24 de dezvoltatori a variat de la
începător la expert.

Eficacitatea practicii TDD a fost analizată folosind următoarele date: (1) timpul utilizat de participanţi
pentru a dezvolta aplicaţia pentru a evalua viteza de dezvoltare şi (2) rezultatele testării funcţionale
de tip black box pentru a evalua calitatea externă. În plus, calitatea cazurilor de test scrise de
dezvoltatorii TDD a fost măsurată utilizând analiza acoperirii codului. Cercetătorii au suplimentat
rezultatele lor utilizând date dintr-un sondaj asupra percepţiei participanţilor asupra randamentului
practicii TDD.

5.2. Validitatea externă


O consideraţie importantă în design-ul cercetării empirice este validitatea externă, abilitatea
rezultatelor experimentale de a fi aplicate mediului din afara situaţiei din studiul de cercetare.
Soliditatea rezultatelor cercetătorilor [13] constă în faptul că experimentul a fost efectuat împreună
cu specialişti aflaţi în propriul mediu de lucru. Cu toate acestea, există cinci limitări importante
pentru validitatea externă a experimentului lor:

 Dimensiunea eşantionului a fost relativ mică (6 perechi pentru grupul TDD şi 6 perechi pentru
grupul de control).
 După trecerea în revistă a rezultatelor din prima rundă, cercetătorii au modificat
instrucţiunile experimentului pentru rundele următoare: (1) s-a accentuat nevoia ca
dezvoltatorii din grupul de control să scrie cazuri de test automate la finalizarea
implementării codului; (2) s-a accentuat ca toţi dezvoltatorii trebuie să trateze condiţiile
pentru erori şi (3) nu s-au oferit nici unui dezvoltator cazurile de test pentru acceptare. Din
nefericire, o singură pereche din grupul de control a creat într-adevăr cazuri de test
automate de valoare, cu toate că au fost însărcinaţi anume în acest sens. Din greşeală, grupul
de control a reprezentat cu mai multă acurateţe “starea practicii” dezvoltării de software în
industrie.
 În toate experimentele, programatorii au lucrat în perechi. Două organizaţii de dezvoltatori
profesionişti utilizau practica pair-programming în dezvoltarea de zi cu zi, iar celălalt grup era
familiarizat cu ea. Prin urmare, cu toate că nu este cerută în TDD, pair-programming a fost
folosită pentru a acomoda obiectivul experimentului (de a evalua eficacitatea practicii TDD în

8
mediul de dezvoltare de zi cu zi). De aceea, rezultatele prezentate în [13] se aplică
combinaţiei TDD cu pair-programming.
 Aplicaţia utilizată în procesul de evaluare a fost de dimensiuni foarte mici (dimensiunea
codului a fost de aproximativ 200 de linii de cod).
 Subiecţii din experiment aveau o experienţă variată în ceea ce priveşte practica TDD (de la
novice la expert). Al treilea set de dezvoltatori profesionişti aveau doar trei săptămâni de
experienţă cu metodologia TDD înaintea experimentului. De aceea, este de conceput ca
abordarea teste-la-început nu este consolidată la aceşti subiecţi.

6. Rezultatele experimentului

6.1. Analiza cantitativă


Calitatea externă a codului şi diferenţele de productivitate între grupul TDD şi grupul de control au
fost analizate şi cuantificate. În plus, acoperirea codului pentru perechile TDD a fost examinată.
Rezultatele acestei analize sunt prezentate în continuare.

6.1.1. Calitatea externă a codului

Au fost dezvoltate 20 de cazuri de test de tip black box pentru a evalua calitatea externă a codului
dezvoltatorilor profesionişti. Cazurile de test au validat gradul în care specificaţiile cerute au fost
implementate şi robusteţea codului (precum capacitatea de a trata erorile). Codul echipelor TDD a
trecut cu succes cu aproximativ 18% mai multe cazuri de test decât cel al perechilor din grupul de
control. Figura 2 [13] înfăţişează diagrama cazurilor de test trecute cu succes. În diagramă, marginile
suprafeţei marchează a 25-a şi a 75-a percentilă, iar linia orizontală din centrul suprafeţei marchează
mediana distribuţiei. Pentru început, valoarea mediană pentru codul dezvoltatorilor TDD este clar
mai mare decât mediana dezvoltatorilor din grupul de control.

Figura 2. Diagrama cazurilor de test trecute cu succes

9
O ipoteză a cercetării [13] era aceea că abordarea TDD furnizează cod cu o calitate externă a codului
superioară. Pe baza analizei datelor realizate, rezultatele experimentale sprijină această idee, însă
validitatea rezultatelor trebuie considerată în contextul limitărilor prezentate anterior.

6.1.2. Productivitatea

Unele persoane sunt sceptice în privinţa timpului suplimentar necesar scrierii şi actualizării cazurilor
de test. La fel cum arată şi Figura 3, perechile TDD au necesitat în medie cu 16% mai mult timp
pentru dezvoltarea aplicaţiei faţă de perechile din grupul de control. Medianele celor două grupuri
sunt aproape egale. Însă, valoarea intervalului superior este mai ridicată pentru dezvoltatorii TDD.

O consideraţie importantă în această analiză o reprezintă aceea că perechile de control au fost rugate
să scrie cazuri de test după ce au dezvoltat codul (într-o manieră tradiţională programează-apoi-
testează). Însă, un singur grup a scris cazuri de test valabile. Aceasta a rezultat într-o comparaţie
neechilibrată a timpului necesitat şi de aici o limitare a studiului. Timpul suplimentar necesitat de
TDD poate fi atribuit duratei dezvoltării cazurilor de test.

Figura 3. Diagrama timpului utilizat de dezvoltatori

Există numeroase beneficii rezultate din crearea cazurilor de test de către dezvoltatorii TDD. În
primul rând, perechile TDD au produs active de test alături de codul de implementare. Aceste active
de test sunt foarte valoroase în viaţa produsului pe măsură ce produsul este îmbunătăţit. În al doilea
rând, codul dezvoltat este testabil. Dacă programele sunt scrise fără o consideraţie continuă pentru a
putea fi testabile automat, scrierea acestor cazuri de test ulterior poate fi foarte dificilă, sau chiar
imposibilă. În al treilea rând, codul care intră în fazele de testare următoare şi care este livrat
clientului are o calitate mai bună. Această calitate mai ridicată reduce costurile de testare şi de
întreţinere. În ultimul rând, durata ciclului total de viaţă poate fi mai mică în iteraţiile următoare
deoarece modificările pot fi realizate mult mai uşor.

O altă ipoteză susţine că programatorii care utilizează TDD sunt mai productivi, din punct de vedere
al timpului necesar pentru finalizarea unui program. Însă, contrar acestei ipoteze, rezultatele

10
experimentului au arătat că dezvoltatorii TDD au necesitat cu 16% mai mult timp faţă de cei din
grupul de control. Validitatea acestor rezultate trebuie considerată în contextul limitărilor discutate.

6.1.3. Corelarea între productivitate şi calitate

În medie, perechile TDD au produs cod de o calitate mai ridicată. Însă, au necesitat în medie un timp
mai lung pentru a finaliza lucrul. Prin analizarea rezultatelor celor 12 perechi s-a descoperit o
corelare moderată între timpul utilizat şi calitatea rezultată. Corelarea Pearson two-tailed a avut o
valoare de 0,661 semnificativă la nivelul 0,019. Această analiză indică faptul că nivelul mai ridicat al
calităţii poate fi rezultatul duratei mai îndelungate necesitate de perechile TDD şi nu de către practica
TDD în sine. Trebuie însă luat în considerare faptul că toate perechile şi-au livrat programele doar
atunci când au considerat că vor rula corect. Perechile TDD au considerat că şi-au finalizat munca
doar atunci când au scris cod de o calitate ridicată împreună cu un set rezonabil de cazuri de test
automate. Perechile din grupul de control au considerat că şi-au terminat sarcina livrând un cod de o
calitate mai scăzută, lipsit în general de cazuri de test automate valoroase.

6.1.4. Acoperirea codului

Una dintre preocupările legate de abordarea TDD este meticulozitatea cazurilor de test scrise de
către dezvoltatorii TDD. Esenţial pentru TDD, nivelul calităţii testelor determină calitatea codului.
Analizarea cazurilor de test pentru acoperirea codului a permis evaluarea calităţii cazurilor de test
scrise de către dezvoltatorii TDD.

Standardul industriei pentru acoperire este în intervalul 80-90%, cu toate că, în cazul ideal,
acoperirea ar trebui să fie de 100% [21]. După cum este înfăţişat şi în Figura 4, dezvoltatorii TDD au
depăşit standardele industriale în toate cele trei tipuri de acoperire de cod. Cazurile de test ale
dezvoltatorilor TDD au atins o medie de 98% pentru metode, de 92% pentru linii de cod şi de 97%
pentru acoperirea ramificaţiilor. Trebuie notat că instrumentul de testare utilizat, JUnit, nu poate
testa metoda main (a codului Java) şi de aceea metoda main a fost exclusă din analiza acoperirii
codului.

Figura 4. Diagrama acoperirii codului

11
6.2. Analiza calitativă
Cercetătorii au considerat productivă confirmarea rezultatelor cantitative cu feedback calitativ din
partea dezvoltatorilor de software participanţi la experiment. A fost organizat un sondaj între cei 24
de dezvoltatori profesionişti administrat înaintea experimentului şi care a constat în nouă întrebări cu
răspunsuri predefinite ce au avut ca scop identificarea părerilor dezvoltatorilor asupra trei puncte de
interes:

1. Cât de productivă este practica pentru programatori?


2. Cât de eficace este practica?
3. Cât de dificil de adoptat este practica?

A fost realizată o analiză amănunţită pentru a determina dacă este validă din punct de vedere
statistic agregarea răspunsurilor pentru cele nouă întrebări în cele trei categorii (productivitate,
eficacitate şi dificultate la adoptare) folosind testul prin coeficientul Alpha al lui Cronbach.
Coeficientul Alpha al lui Cronbach măsoară nivelul consistenţei răspunsurilor în cadrul unui sondaj de
opinie. Acesta oferă indicii dacă toate întrebările dintr-o categorie (de exemplu, categoria
productivitate) măsoară acelaşi atribut şi dacă indivizii ar trebui să răspundă din acest motiv la toate
întrebările din cadrul categoriei în mod similar. Rezultatele testului Alpha au indicat validitatea
agregării celor nouă întrebări în cele trei categorii. Semnificaţia statistică a fiecărui răspuns a fost
apoi evaluată pentru fiecare categorie, utilizând testul Rho al lui Spearman. Toate răspunsurile din
sondaj au fost semnificative din punct de vedere statistic la nivelul 0,01 (p < 0,01).

În ceea ce priveşte întrebările legate de productivitatea programatorului, o majoritate covârşitoare a


dezvoltatorilor a considerat că abordarea TDD facilitează o înţelegere mai bună a cerinţelor (87,5%) şi
reduce efortul pentru debugging (95,8%). Cu toate acestea, doar jumătate dintre dezvoltatori au fost
de părere că TDD conduce la o durată de timp mai redusă pentru dezvoltarea codului. Luând în
considerare media comentariilor pozitive, aproximativ 78% dintre dezvoltatori au considerat că
practica TDD îmbunătăţeşte productivitatea de ansamblu a programatorului.

Legat de întrebările referitoare la eficacitate, 92% dintre dezvoltatori au afirmat că TDD produce cod
de o calitate superioară, 79% au considerat că TDD promovează un design mai simplu, iar 71% au fost
de parere că abordarea a fost perceptibil mai eficientă. Astfel, agregarea acestor rezultate indică
faptul că 80% au considerat metodologia TDD eficace.

Răspunsurile dezvoltatorilor la întrebările referitoare la dificultăţile în adoptarea abordării indică


unele motive de îngrijorare. 56% dintre dezvoltatorii profesionişti au fost de părere că utilizarea
gândirii TDD a fost dificilă. O minoritate (23%) a atras atenţia asupra faptului că lipsa unei faze iniţiale
de design în TDD reprezintă un impediment. Realizând o medie a răspunsurilor, 40% dintre
programatori au considerat că există dificultăţi în adoptarea practicii TDD.

Pe baza sondajului de opinie şi a comentariilor venite de la studenţi, s-a putut concluziona că


dezvoltatorii consideră că TDD este eficientă în ceea ce priveşte calitatea codului şi îmbunătăţeşte
productivitatea. Utilizarea gândirii TDD este însă dificilă iniţial. În plus, o parte dintre programatori şi-
au exprimat îngrijorarea privind creşterea timpului pentru dezvoltare necesar scrierii cazurilor de
test.

12
7. Concluzii
O serie de experimente a fost coordonată pentru a examina practica TDD. Mai exact, următoarele
ipoteze au fost testate şi s-au obţinut concluziile corespondente, sub rezerva limitărilor studiului:

 Abordarea TDD se pare că furnizează cod de o calitate externă a codului superioară,


măsurată prin conformarea la un set de cazuri de test black box prin comparaţie alături de
codul dezvoltat cu o practică mai tradiţională precum modelul cascadă.
 Rezultatele experimentului au arătat că dezvoltatorii TDD au avut nevoie de un timp cu 16%
mai mare faţă de cei din grupul de control. Diferenţa în performanţele echipelor este însă
mare, iar aceste rezultate sunt doar direcţionale. În plus, perechile din grupul de control nu
au creat nici un caz de test automat reuşit (cu toate că au fost însărcinaţi cu aceasta), fapt
care dezechilibrează comparaţia.
 În medie, 80% dintre dezvoltatorii profesionişti au afirmat că TDD este o abordare eficace, iar
78% au fost de părere că abordarea îmbunătăţeşte productivitatea programatorului.
Rezultatele sondajului sunt semnificative statistic.
 Calitativ, studiul de cercetare a descoperit că abordarea TDD facilitează un design mai simplu
şi că lipsa unui design iniţial nu reprezintă un impediment. Pentru unii, însă, trecerea la
gândirea TDD este dificilă.

Aceste rezultate trebuie considerate în cadrul limitărilor experimentelor coordonate. Alte studii
controlate desfăşurate pe o scară mai mare în industrie şi în mediul academic ar putea consolida sau,
dimpotrivă, demonstra netemeinicia acestor rezultate.

13
Referințe
[1] K. Beck. Extreme Programming Explained: Embrace Change, Second Edition. Boston,
Massachusetts, SUA, 2004, AddisonWesley.

[2] K. Beck și M. Beedle, ș.a. Manifesto for Agile Software Development, 31.05.2010,
http://www.agilemanifesto.org.

[3] G. Larman și V. R. Basili. Iterative and Incremental Development: A Brief History. IEEE Computer
36(6): 47 - 56, 2003.

[4] D. Astels. Test-Driven Development: A Practical Guide. Upper Saddle River, New Jersey, SUA,
2003, Prentice Hall.

[5] K. Beck. Test-Driven Development By Example. Boston, Massachusetts, SUA, 2003,


AddisonWesley.

[6] K. Beck. Aim, Fire. IEEE Software 18(5): 87 - 89, Septembrie/Octombrie 2001.

[7] M. Siniaalto. Test Driven Development: Empirical Body of Evidence, 2006, Information Technology
for European Advancement.

[8] S. W. Ambler. Introduction to Test Driven Development (TDD), 31.05.2010,


http://www.agiledata.org/essays/tdd.html.

[9] P. Abrahamsson, A. Hanhineva ș.a. Improving Business Agility Through Technical Solutions: A Case
Study on Test-Driven Development in Mobile Software Development. Business Agility and
Information Technology Diffusion. R. Baskerville, L. Mathiassen, J. Pries-Heje și J. DeGross. New York,
SUA, Springer: 227 – 243, 2004.

[10] M. Fowler. Refactoring. International Conference on Software Engineering, Orlando, Florida,


SUA, 2002, ACM Press.

[11] D. Gelperin și W. Hetzel. Software Quality Engineering. Fourth International Conference on


Software Testing, Washington D.C., SUA, iunie 1987.

[12] D. Chaplin. Test First Programming, TechZone, 2001.

[13] B. George și L. Williams. An Initial Investigation of Test Driven Development in Industry.


Proceedings of the 2003 ACM Symposium on Applied Computing, Melbourne, Florida, SUA, 2003,
ACM Press.

[14] E. Dustin, J. Rashka şi J. Paul. Automated Software Testing. Reading, Massachusetts: Addison
Wesley, 1999.

[15] B. W. Boehm. Software Engineering Economics. Englewood Cliffs, NJ: Prentice-Hall, Inc., 1981.

[16] M. M. Muller şi O. Hagner. Experiment about Test-first programming, Empirical Assessment In


Software Engineering EASE '02, Keele, aprilie 2002.

14
[17] B. George. Analysis and Quantification of Test Driven Development Approach, North Carolina
State MS Thesis, 2002.

[18] L. A. Williams. The Collaborative Software Process. Salt Lake City, UT: Department of Computer
Science, SUA, 2000.

[19] C. R. Martin. Advanced Principles, Patterns and Process of Software Development: Prentice Hall,
2001.

[20] W. W. Royce. Managing the development of large software systems: concepts and techniques,
IEEE WESTCON, Los Angeles, CA, SUA, 1970.

[21] S. Cornett. Code Coverage Analysis. Bullseye Testing Technology, 2002.

15

S-ar putea să vă placă și