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

11:08:00CULTURA, DAR ȘI LIPSA EI —» Leo Butnaru
17:14:00Cum Centrul pentru persoanele fără adăpost din Chișinău devine un model de eficiență energetică ✨ —» Sandu GRECU
08:43:48CMB Rose Tasting: 27-29 martie, Italia —» Fine Wine
05:44:00DIN POEZIA LUMII —» Leo Butnaru
05:52:30DIN ITERSECȚII —» Leo Butnaru
20:35:00Parlamentul a votat modernizarea Serviciului de Protecție și Pază de Stat pentru alinierea la standardele europene de securitate ⚔️ —» Sandu GRECU
14:33:09Campania Wikipedia #Maraton2026 —» Biblioteca de Arte 'Tudor Arghezi'
09:42:37Radu Hossu: ruși încercuiți în Ucraina | Update Ucraina și Iran —» Curaj.TV | Media alternativă
07:27:56DIN IMAGINAȚIA COPILULUI —» Leo Butnaru
06:46:27LA PURTĂTOR —» Leo Butnaru
15:08:49RESENTIMENTE ȘI ILUZIA EGALIZĂR —» Leo Butnaru
07:11:38Castel Mimi lansează noutățile din roada 2025 —» Fine Wine
04:56:35DIN PASIENȚE —» Leo Butnaru
14:58:00Igor Picușciac: I-am dat cu sticla în cap lui Tâmbur... 🔥🔥🔥 —» Sandu GRECU
14:42:00Lilian Carp denunță manipulările și mesajele contradictorii ale primarului Ion Ceban privind criza ecologică de pe râul Nistru —» Sandu GRECU
18:32:00Loteria Națională a Moldovei lansează newsletter-ul oficial 🗞️ —» Sandu GRECU
17:59:00Producătorii de vinuri de autor din Republica Moldova participă la RO-Wine 2026, la Cluj-Napoca 🥂 —» Sandu GRECU
15:19:35Ghici cine a primit despăgubiri pentru robie? —» Curaj.TV | Media alternativă
12:07:51„Smoothie” din tescovină: Purcari duce Moldova în liga europeană a cercetării —» Fine Wine
10:54:16Odeon —» Andrei LANGA. Blogul personal
05:17:14DESPRE JURNALUL UNEI EPOCI —» Leo Butnaru
11:04:23Inițiativa „Feteasca Generation”, lansată la Prowein —» Fine Wine
08:55:26Reînvie o legendă? Amaro de la Valea Perjei —» Fine Wine
05:36:22ECART ȘI APROPIERE —» Leo Butnaru
14:40:00Loteria Națională a Moldovei lansează instrumente de accesibilitate digitală pe platforma lnm.md —» Sandu GRECU