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

20:59:44Fără Titlu —» Путепроводные Заметки
20:57:02Fără Titlu —» Путепроводные Заметки
15:17:57Felicitare la Finalul Anului Școlar 2024 -2025 —» Liceul Teoretic “Mihail Sadoveanu”, Călăraşi
10:27:31Fără Titlu —» Путепроводные Заметки
16:57:30Fără Titlu —» Путепроводные Заметки
14:57:00Cum recunoști un text scris de AI, dar neredactat de om - ghid pentru cititori și jurnaliști —» Eleonora Lisnic în versuri
13:43:00ATENȚIE la înșelătoriile online! Cursurile serioase de Inteligență Artificială sunt organizate de instituții acreditate —» Eleonora Lisnic în versuri
13:20:16Fără Titlu —» Путепроводные Заметки
07:17:36300 de invitați sunt așteptați, în iunie la Chișinău, la Congresul mondial al vinului —» Fine Wine
06:42:41Ce înseamnă „Eu sunt cu voi şi nimeni împotriva voastră”? —» Portalul Tineretului Ortodox din Moldova
04:42:53Fără Titlu —» Путепроводные Заметки
14:48:42Anunț de contractare a furnizorilor de echipamente și utilaje în cadrul proiectului „Abilitarea tinerilor antreprenori din Republica Moldova” —» Asociaţia Obştească "Demos"
13:49:13Fără Titlu —» Путепроводные Заметки
11:27:11Muzică de Fanfara —» CHIŞINĂU MUZICAL | Blogul Bibliotecii de Arte "Tudor Arghezi"
10:09:32Vinul care face bine: Sapiens —» Fine Wine
08:42:06Invitație la tender: Servicii de instruire și mentorat pentru tineri antreprenori din regiunea de nord a Republicii Moldova —» Asociaţia Obştească "Demos"
08:41:07Crama Neamțu lansează recolta 2024 —» Fine Wine
07:44:02#DirectEuropa‬ cu Ileana Răcheru —» Curaj.TV | Media alternativă
04:49:40Fără Titlu —» Путепроводные Заметки
20:40:00Kinderland —» Andrei LANGA. Blogul personal
20:40:00Kinderland —» Andrei LANGA. Blogul personal
13:50:29Fără Titlu —» Путепроводные Заметки
13:41:00Măr —» Andrei LANGA. Blogul personal
13:41:00Măr —» Andrei LANGA. Blogul personal
11:46:00Prompt AI - exemplu util, simplu și adaptabil. GhatGPT explică editarea unui video în CapCut —» Eleonora Lisnic în versuri