Care-i treaba cu TDD-ul

Care-i treaba cu TDD-ul

duminică, 10 octombrie 2010, 10 al lunii a 10-a a anului 2010 :)

Ce m-a apucat? Păi hai să vă povestesc pentru ce mi-a trebuit mie sucitura asta cu TDD-ul. O să încep cu partea uşoară, care se vede cu ochiul liber: testarea automatizată.

Testarea automatizată

De obicei, după vreo două săptămîni de lucru la un proiect, se adună destul de multă funcţionalitate şi devine din ce în ce mai greu să verifici tot după fiecare modificare, mai ales dacă se întîmplă schimbări care afectează mai multe părţi ale aplicaţiei. Şi dacă ai destul curaj (?) să nu verifici tot, stă în subconştient un vierme care te roade tot zicînd “oare nu s-o fi stricat ceva pe undeva?”. Şi dacă mai e o aplicaţie care e deja în producţie şi se lucrează la modificări, atunci pericolul, şi repectiv îngrijorarea, e şi mai mare. Şi nu ştiu cum pe voi, dar pe mine tare mă consumă îngrijorarea asta. E o stare de stres, şi stresul nu numai că îţi mănîncă o grămadă de energie, dar te şi împiedică să gîndeşti bine, nemaivorbind creativ.

Şi, dacă mă duce capul cum să pun la punct un mecanism de testare automatizată, cum povesteam în articolul precedent, atunci dorm cu mult mai liniştit: după fiecare modificare oricît de mică sau oricît de mare, pot verifica foarte repede dacă mai merge totul cum mergea.

Evident nu pot scrie din start setul ideal de verificări, dar, e OK, imediat cum detectez o scăpare, scriu repejor un test şi gata! iar sunt la linia de plutire. Adică orice problemă mă deranjează doar o singură dată.

TDD—Programarea ghidată de teste

Deci e foarte clar că testarea automatizată îţi uşurează viaţa de programator. Kent Beck însă a mers mai departe de atît şi a inventat TDD-ul: Test Driven Development. Şi şmecheria consta în aceea că înainte de a scrie orice bucăţică de cod, să scrii un test care verifică că codul respectiv (viitor) face ce trebuie să facă. Şi una dintre esenţele acestei abordări este că îţi clarifici foarte bine şi foarte exact ce vrei să faci. Mie de exemplu mi s-a întîmplat de foarte multe ori să încep să programez ceva fără să am o idee clară despre ce anume şi cum urmează să funcţioneze mecanismul respectiv. Desigur şi asta e normal la stadiul de explorare, partea în care doar pipăi şi încerci să-ţi faci o impresie despre ce şi cum se poate face, de exemplu cînd încerci o tehnologie nouă, dar, cînd scrii cod care mai tîrziu se duce în producţie aatunci e mai bine să ştii ce vrei să faci. :)

O altă chestie bună care rezultă din TDD e că de la bun început te gîndeşti cum să scrii codul ca să-l poţi verifica. Asta e elementar de înţeles şi de închipuit atunci cînd te gîndeşti la funcţii şi la clase. Un exemplu banal: vrei o funcţie care să-ţi spună cîte zile în urmă e o anumită dată. Dacă funcţia s-ar numi daysSince testul scris cu QUnit ar arăta cam aşa:

test('Funcţia care arată cîte zile în urmă e o dată', 1, function() { var yesterday = Date('2010-10-09'); equals(daysSince(yesterday), 1, 'A trecut o zi de ieri'); }

După definirea testului, un pas important în TDD e să-l rulăm să vedem că nu trece şi să ne asigurăm că funcţia nu este deja implementată de altcineva. Deci executăm testele: roşu. Bun!

Acum ştim că funcţia ar trebui să ne întoarcă 1 dacă i-am da ca argument data de ieri. În cazuri de complexitate mai mare, nenea Kent ar merge pe calea “fake it till you make it” implementînd funcţia daysSince cam aşa:

function daysSince(date) { return 1; }

Pare anectodic, dar asta respectă principiul “the simplest thing that could possibly work”, şi dacă precăutăm cazul concret pe care-l avem în test, atunci, funcţia face suficient cît să-l treacă. Sună a braşoavă, dar, aveţi răbdare, toate se leagă mai tîrziu foarte bine. ;) Pe deasupra, dacă avem vreo problemă cu implementarea asta, avem la dispoziţie următorul pas din ciclul TDD: refactorizarea. Acum cel mai important lucru de pe lume e să avem verde la teste.

Dar cum la noi funcţia e destul de simplă ca algoritm, o să încercăm să scriem o implementarea reală din prima. Cel mai simplu algoritm care-mi vine în minte e să transform data care vine ca argument în timestamp, transform şi data curentă în timestamp, fac scăderea, împart la numărul de milisecunde dintr-o zi, şi rotunjesc aritmetic:

function daysSince(date) { var dateTimestamp = date.getTime(), currentTimestamp = (new Date).getTime(), millisecondsPerDay = 86400000, difference; difference = (currentTimestamp - dateTimestamp) / millisecondsPerDay; return Math.round(difference); }

Gata. Dacă astea dunt cerinţele, asta e implementarea. Cînd apar alte cerinţe, scriu alte teste şi iar sunt asigurat că funcţia face ce trebuie să facă, iar dacă nu face, o să aflu imediat.

Da, dar, ce pot să fac eu cu TDD-ul în lucrul de zi cu zi?!

Într-adevăr, e una să testezi o funcţie, şi alta e să încerci să testezi codul JavaScript care există de obicei în aplicaţiile web, sau cum să-l scrii testabil. Hai să vedem. Vreau să verific că atunci cînd dau click pe un buton mi se afişeză nişte informaţie suplimentară despre ceva.

test('Verificăm butonul', 2, function() { ok($('div.moreDetails').is(':not(:visible)'), 'Detaliile nu sunt vizibile înainte de a da click pe buton'); $('button.showMoreDetails').click(); ok($('div.moreDetails').is(':visible'), 'Detaliile sunt vizibile după ce se dă click pe buton'); });

Nu e complicat deloc cînd merge vorba de chestii sincrone ca aceasta. Treaba e un pic mai delicată cînd avem chestii asincrone de genul la AJAX, de exemplu dacă detaliile care trebuei afişate, trebuie să le încarc de pe server şi această abordare nu mai merge pentru că după ce simulez un click pe buton, datele încă nu sunt încărcate. Pentru a testa chestii asincrone QUnit are teste asincrone.

test('Verificăm butonul asincron', 2, function() { stop(1000); ok($('div.moreDetails').is(':not(:visible)'), 'Detaliile nu sunt vizibile înainte de a da click pe buton'); $('div.moreDetails').bind('loaded', function() { ok($('div.moreDetails').is(':visible'), 'Detaliile sunt vizibile după ce se dă click pe buton'); start(); }); $('button.showMoreDetails').click(); });

Aici se zice aşa: cînd div.moreDetails o să-mi zică că s-au încărcat datele, atunci o să verific dacă s-au afişat. Pentru ca asta să funcţioneze, în aplicaţie trebuie să declanşăm evenimentul loaded pe div-ul respectiv, şi asta se face elementar cu jQuery:

$('button.showMoreDetails').bind('click', function() { var details = $('div.moreDetails'); details.load('details.html', function() { details.trigger('loaded'); }); });

În aceeaşi manieră se pot testa mecanisme asincrone de orice complexitate.

Pe scurt (mi se termină timpul ;)) TDD-ul ne ghidează spre a scrie cod testabil, ceea ce duce la o mult mai uşoară automatizare a testelor.


Sursa
2010-10-10 17:47:00



Comenteaza





Ultimele 25 posturi adăugate

18:04:44UN POET RUS CÂNDVA EXPULZAT DIN ROMÂNIA —» Leo Butnaru
14:43:17CEREȚI vs. CERE-ȚI – când punem cratima? —» Moldova Creștină
13:17:10UN PROZATOR ȘI POET FRANCEZ IMPORTANT —» Leo Butnaru
10:05:33Graduation @ #Precept Institute for South Sudan Refugees in Uganda 🇺🇬 —» Moldova Creștină
09:35:01”Nu te baza pe alții! Privește, învață, fă și taci!” sau Despre cum să fii optimist —» Sunt MAMĂ!
09:20:02De ce copiii mei au hainele murdare? —» Sunt MAMĂ!
17:02:42DE LA POEȚI ANTICI PÂNĂ SPRE AI NOȘTRI... —» Leo Butnaru
12:01:45De ce reușesc să fac atât de multe lucruri timp de o zi —» Sunt MAMĂ!
11:50:40Disciplinile umanistice și posibilitățile de inserție profesională —» Centrul Comunitar Instruire, Acces Informaţie Călăraşi
10:27:43Vizita de lucru a secretarului de stat Gheorghe Cârciu în Franța —» Elena Robu
08:00:39Cum a ajuns profesia de cercetător una din cele mai instabile în RM —» Gheorghe Cuciureanu
05:48:09Serviciul „Eco responsabil”, ediția a II-a —» BiblioCity
02:31:03©️ Tu poți —» Licurici de suflet
09:57:45Despre „Demonii. Spovedania lui Stavroghin” de la Teatrul din Cluj —» Andrei Albu - omul alb cu gînduri negre
08:19:54Moldova a găsit soluția pentru eroarea 404. În vin! —» Fine Wine
13:09:41Guvernul vrea să închidă robinetul în capitală și lansează site-ul apă.md —» Nicolae Federiuc
10:00:17Poezie „Oameni ai credinței” —» Moldova Creștină
06:31:21REZILIENȚA SOCIALĂ A CONTINENTULUI MOLDAV —» Daniel Lachi
18:53:13PATIMILE DUPĂ DOSTOIEVSKI —» Leo Butnaru
06:25:22PUTINIȘTII TREBUIE EXTIRPAȚI! —» Daniel Lachi
05:24:1710 principii de evanghelizare și ucenicie din Ioan 4-11 —» Moldova Creștină
18:59:39Bugetul IP Gimnaziul "Victor Coțofană " pe anul 2023 —» Blogul elevilor din satul Chetrosu
18:54:44Informație cu privire la formarea bugetului pentru anul 2023, în IP Gimnaziul "Victor Coțofană" —» Blogul elevilor din satul Chetrosu
18:48:13Raport referitor la executarea bugetului pentru anul bugetar 2022 —» Blogul elevilor din satul Chetrosu
14:36:50POEME PRIN ANI / ANTOLOGIE DE ETAPĂ #12 (30 de texte) —» Leo Butnaru