Sunt sigur că oricine a lucrat într-o companie software a auzit cel puțin o dată această întrebare sau poate s-a gândit la ea. Dacă analizăm întrebarea mai în profunzime, vom constata că nu are sens, cele două tipuri de teste având rol complementar. Avem nevoie de teste Acceptance și în zilele noastre am vrea să fie automatizate.
Adevărata întrebare, care are și sens, și pe care, de asemenea, ați mai auzit-o este „Cine trebuie să implementeze testele Acceptance?” iar răspunsul la ea depinde de la o companie și de la o echipă la alta. În opinia mea, care din fericire coincide cu părerea companiei și a echipei (yey!), toți membrii echipei ar trebui să o facă. Da, chiar și PM-ul are un rol foarte important în formularea cerințelor într-un format ușor de tradus în Gerkin. De câte ori discutăm despre asta, o altă întrebare iese la iveală într-un fel sau altul: „Dar dacă toată echipa scrie teste de tip Acceptance, n-ar trebui să scrie toată echipa și cod?”. Sigur că da, tester-ii ar trebui și chiar scriu cod. Testele automate Acceptance se scriu prin cod, trec prin același proces de review și fac parte din code base. Vor lua tester-ii și task-uri de development în afară de automatizarea testelor? Unii da, alții nu, dar nu suntem în situația unui deficit de development care să trebuiască acoperit. Sigur ați auzit că pentru fiecare tester într-o echipă, sunt 3-5 dezvoltatori. Ați auzit aceasta pentru că în general e adevărat. Deși cu siguranță există excepții, în compania noastră, cam acesta este raportul. Testerul, QA-ul, SDT-ul sau oricare alt titlu există în compania voastră, este în general destul de solicitat, încât dacă ar lua și task-uri de development, s-ar crea un deficit pe partea de testare care ar putea afecta proiectul. Nu mă înțelegeți greșit, nu vreau să mă plâng, îmi place ritmul alert, dar din anumite motive dezvoltatorii nu-și prea doresc să scrie teste. Poate simt că și-ar pune la îndoială calitatea codului sau a competenței, dar pentru un dezvoltator experimentat, testele automate adaugă valoare muncii lor și economisesc timp la validare.
Pe de altă parte, dacă și developer-ii vor scrie teste Acceptance atunci tester-ii dedicați echipei vor putea să investească mai mult timp în alte arii, spre exemplu în a face deploy-uri, ceea ce mai nou se întâmplă la un click de buton. După cum știti în lumea dezvoltării de software, principalul scop este de a avea medii automatizate, adoptând astfel paradigma continous delivery. În felul acesta, dacă și dezvoltatorii vor scrie teste Acceptance și toate vor fi integrate în deployment pipeline sau nightly deploy, toate acoperind toate funcționalitățile aplicației, atunci ce ar mai avea de făcut tester-ul? Nu s-ar ajunge atunci într-o lume în care nu ar mai fi așa de clar delimitările între rolul de developer sau tester? Bineînțeles că în lumea actuală nu poți spune că multe proiecte chiar ajung la maturitatea aceasta, în care continous delivery-ul să fie atins la maxim și totul să meargă lejer către live. În cazul acesta, tester-ul are și testare manuală de făcut, ceea ce îi ocupă destul de mult timp având în vedere multitudinea de feature-uri pe care le livrează o echipă de developer-i. Deci, trecând dintr-o utopie și coborând cu picioarele pe pământ, în lumea actuală cel mai indicat ar fi ca fiecare developer să fie responsabil să își acopere cu teste Acceptance și Unit cel puțin, feature-urile pe care le livrează.
Poate vă întrebați unde vreau să ajung cu aceasta. Vreau să scrieți mai multe teste? Bineînțeles că vreau, sunt tester, dar mai mult de atât, vreau să vă placă și să le apreciați valoarea. Probabil deja ați descoperit valoarea testelor Unit, deși încă vă agasează puțin comentariul cu „n-ar trebui să avem teste Unit aici?” din pull request-uri, și v-ați convins că o dată scrise vă fac viața mai ușoară. Când vine vorba de teste Acceptance, beneficiile merg mult mai departe. Nu numai că vă descoperă propriile greșeli, dar le descoperă și pe ale altora, și ce poate fi mai satisfăcător decât arătatul cu degetul? Lăsând gluma la o parte, scriind teste Acceptance veți fi forțați să înțelegeți mult mai bine cerințele de business, vă vor face să conștientizați limitările și problemele de infrastructură, veți avea acoperire end to end a integrării și totodată niște indicii de performanță.
Și atunci de ce nu scriem cu toții doar teste Acceptance? Pentru că lumea nu este desenată doar cu alb și negru, are multe nuanțe de gri (probabil mai mult de 50) iar fiecare tip de test are rolul său, beneficiile și limitările sale. Am început discuția doar cu teste Aceeptance și vreau să vă conving că scrierea lor vă va face un developer mai bun. Voi încerca să vă „vând” acest tip de teste. Nu voi repeta mantra „mai ieftin, mai rapid, mai stabil” pe care ați auzit-o sau citit-o de nenumărate ori, dar voi încerca să vă prezint o viziune mai personală provenită din experiența mea de până acum.
Puteți acoperi multe funcționalități cu un singur test de tip Acceptance gândit și scris bine. Pentru o aplicație web uzuală, ați putea acoperi majoritatea funcționalităților critice pentru business în aproximativ 10 teste. Acestea vor fi integrate în pipeline și vă vor asigura încrederea în fiecare release care ajunge în producție, încredere fără de care nu veți putea avea „continuous delivery”. Veți găsi de cele mai multe ori probleme de dependențe, integrare sau chiar baze de date (pentru că ați acoperit deja logica de bază cu teste Unit, nu? ), dar acestea vor fi probleme importante. Sunt sigur că într-o lume perfectă, codului perfect i se face deploy perfect pe mașinile virtuale perfecte și va rula perfect pe toate mediile perfecte, dar noi nu trăim într-o lume perfectă. În lumea reală, mereu folosim API-ul altcuiva care face mereu schimbări și nu ne anunță (și de ce ar face-o?), sau vreo mașină din Azure are probleme sau a fost greșit configurată, sau cineva a mutat o coloană în baza de date sau un milion de alte probleme ce pot să apară (și care spune Murphy că vor apărea la un moment dat) iar testele Acceptance vor descoperi toate aceste probleme. Puteți face aceasta cu teste Unit? Poate vă gândiți: „dar treaba mea e să scriu cod de calitate!”. Nu chiar... Treaba noastră, a tuturor, este să LIVRĂM cod de calitate și dacă ne vom limita la mentalitatea de muncitor pe linia de producție care se ocupă doar de bucățica lui, așa vom fi și tratați.
O dată ce ați început să scrieți teste Acceptance, veți înțelege mult mai bine logica de business. Va trebui să înțelegeți exact cum ar trebui un utilizator să vă folosească aplicația și s-ar putea chiar să găsiți lucruri de înbunătățit. PM-ul a creat niște flow-uri și și-a imaginat un produs final. Voi le-ați implementat conform cerințelor. După ce scrieți teste Acceptance veți descoperi cum puteți face flow-urile mai eficiente pentru că veți vrea ca testele să ruleze cât mai repede și vor deveni evidente punctele în care aplicația se mișcă prea lent sau unde ar putea fi folosită mai ușor. Cât este de dificil să scrieți teste Acceptance ? Nu poate fi prea greu dacă pot să le scrie tester-ii, nu? Scrierea e de fapt partea ușoară. Spre deosebire de teste Unit, folosirea unei mașini virtuale sau build agent pentru a rula un browser controlat printr-un webdriver pentru a testa o aplicație web poate fi uneori puțin instabil. Aici intră în scenă partea de întreținere și debugging. Vă rog nu vă lăsați descurajați de micile probleme, toată lumea se confruntă cu ele la un moment dat, dar dacă perseverați, veți învăța să evitați problemele uzuale și în final veți avea niște teste stabile și valoroase. Investiți timp și efort și recompensele vor veni în scurt timp.
Ați ajuns să scrieți teste Acceptance și să vă placă? Acum problema este că aveți prea multe. Nu le mai puteți folosi ca teste smoke la deploy pentru că rulează 2 ore. Ce puteți face? Sunteți la punctul în care ar trebui să investiți timp într-un nightly build. Deși se numește nightly build, nu înseamnă că aveți nevoie de un nou build al întregii soluții. Puteți rula doar testele, la un moment stabilit din noapte, pe ultimul build ajuns în CI iar rezultatele vă vor aștepta dimineață. Să vedeți raportul verde în timp ce vă beți cafeaua proaspăt făcută e cea mai plăcută senzație, dar nu vă atașați prea tare de ea, pentru că în ziua următoare e posibil să aveți și un test roșu, ceea ce e bine pentru că acesta e rolul lor și motivul pentru care le-ați scris. Pe termen lung vă vor face aplicația mai bună.
Pentru a finaliza „vânzarea”, voi încerca să vă ofer câte un sfat personalizat. Dacă sunteți tester-i, începeți sau continuați să scrieți teste Aceeptance automate. Vă vor face munca mai ușoară și veți înțelege mai bine ce fac developer-ii. Dacă sunteți developer-i, nu vă feriți de testele automate Acceptance, din toate motivele ce le-am dat până acum și pentru a livra (nu doar a coda) aplicații excelente. Dacă sunteți product manager-i, uitați-vă la cum sunt scrise câteva teste și încercați să imitați formulările BDD. Restul echipei va aprecia efortul și vă vor înțelege mai bine viziunea. Dacă faceți deja tot ce am descris până acum, sunteți grozavi și țineți-o tot așa!
După ce ați înțeles motivul pentru care scriem teste Acceptance, imaginați-vă valoarea enormă pe care o aduce întâlnirea cu testele Unit. Din punctul de vedere al unui developer, pentru ca proiectul să-și păstreze valoarea pe termen lung, va trebui să-l întrețineți și să adăugați funcționalități provenite din feedback-ul utilizatorilor sau alte nevoi. Să presupunem că nu aveți foarte mult cod acoperit de teste Unit și urmează să adăugați o funcționalitate importantă într-o zonă critică a aplicației. Veți încerca să o implementați în cel mai eficient mod posibil, și veți avea tendința de a refactoriza puțin codul existent pentru a putea integra logica nouă. Totul merge bine, sunteți mulțumiți de noua funcționalitate, vă bucurați că v-ați încadrat în timpul alocat iar în momentul următor vine PM-ul sau un utilizator plângându-se că nu mai funcționează o parte veche a aplicației. Desigur, având teste Acceptance vă veți aștepta ca problema să fi fost descoperită, dar dacă respectiva funcționalitate nu a fost suficient de importantă încât să fie acoperită de teste Acceptance ? Trebuie să recunoaștem că se poate întâmpla. Chiar și încercând să acoperim cât mai mult cu teste Unit, s-ar putea să existe bucăți mici de logică neacoperită pentru că suntem oameni și facem greșeli. Mi s-a întâmplat să adăugăm logică într-un endpoint al unui API, bucata de cod să nu fie suficient acoperită de teste Unit, iar testele să nu fie rulate la deploy dintr-o eroare. Am ajuns aproape în producție, trecând de CI cu succes și având noroc cu testele Acceptance din pre-producție, unde unul dintre ele nu a trecut. După aproape o oră de investigare a log-urilor, a rezultatelor testelor, a stack trace-ului, a modificărilor de bază de date și accesul API, am ajuns la cel mai profund nivel din aplicație, o parte dintr-o metodă a unei clase pe un serviciu unde developer-ul a ratat o porțiune de logică care returna „not found” fără niciun motiv.
Dacă vă gândiți că într-o asemenea situație, testele Acceptance chiar au valoare, s-ar putea să vă gândiți și că problema ar fi putut fi găsită de către developer chiar și înainte de pull request. Într-adevăr, în astfel de cazuri testele Unit fac munca mai ușoară atât pentru tester cât și pentru developer în viitor, când va putea adăuga orice funcționalitate nouă fiind sigur că nu a afectat nimic dacă la rularea testelor Unit, totul este validat. Pe lângă aceasta, testele Unit ajută foarte mult la designul codului și arhitectura proiectul, obligându-vă să scrieți componente decuplate, urmând principiile SOLID și design pattern-urile aplicabile proiectului vostru. Toate aceste beneficii, vin și cu acela de a putea avea o documentație pentru developer-i, prin care aceștia pot citi cod(testele Unit) și înțelege ce face componenta respectivă.
Ce rămâne de făcut acum că aveți instrumentele pentru a compara și a găsi balanța între diferitele tipuri de teste automate? Rămâne doar să vă antrenați capacitatea de a decide ce e mai bun pentru proiectul vostru. În teorie, toate tipurile de testare ajută și cu cât avem mai multe, cu atât vom dormi mai liniștiți, dar în realitate, nevoile proiectului vă vor dicta strategia de testare pe care trebuie să o adoptați. De fapt, trebuie doar să vă consultați cu PM-ul, arhitectul sau tech lead-ul legat de valoarea pe care o veți aduce proiectului dacă implementați mai multe tipuri de testare și în ce proporții. Nu vrem nici să cădem în cealaltă extremă și să investim prea mult timp în implementarea de teste care nu aduc valoare cu riscul de a nu mai livra funcționalitățile cerute de business. Dacă toată echipa implementează și teste Acceptance , atunci puteți avea încredere în aplicație și în fiecare live release.
Experimentați! Scrieți teste Unit valoroase pentru a avea cod curat și ușor de întreținut chiar și atunci când poate nu veți fi în cea mai bună formă și veți mai avea scăpări. Scrieți teste Acceptance valoroase pentru business, indiferent dacă sunteți tester sau developer. Încercați să vă cunoașteți aplicația de sus până jos, în acest fel toate noile funcționalități vor fi mai ușor de implementat.
Developer-ii fericiți vor avea tester-i fericiți care vor avea product manager-i fericiți și în final utilizatori fericiți, iar aceștia vor face lumea mai bună!
de Iulia Bicu
de Vlad Vesa