Test Driven Development

15
1 Test Driven Development Alexandru Angelescu Facultatea de Informatică, Universitatea “Al. I. Cuza” Iași, România [email protected] 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

Transcript of Test Driven Development

Page 1: Test Driven Development

1

Test Driven Development

Alexandru Angelescu

Facultatea de Informatică, Universitatea “Al. I. Cuza” Iași, România

[email protected]

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

Page 2: Test Driven Development

2

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

Page 3: Test Driven Development

3

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

Page 4: Test Driven Development

4

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ă

Page 5: Test Driven Development

5

ș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

Page 6: Test Driven Development

6

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.

Page 7: Test Driven Development

7

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

Page 8: Test Driven Development

8

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

Page 9: Test Driven Development

9

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

Page 10: Test Driven Development

10

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

Page 11: Test Driven Development

11

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

Page 12: Test Driven Development

12

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.

Page 13: Test Driven Development

13

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.

Page 14: Test Driven Development

14

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.

Page 15: Test Driven Development

15

[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.