Atunci când un proiect software trebuie să fie supus în premieră unui testări automate, probabil că primul lucru la care ne gândim este folosirea unui software comercial destinat tipului de software care urmează a fi testat. De foarte puține ori avem în vedere sau avem curajul să abordam, o soluție de testare automată bazată exclusiv pe componente gratuite și open source, deși în final putem obține rezultate mult mai elegante și mai eficiente comparativ cu soluția comercială.
În funcție de experiența profesională a celor implicați și ținând cont de tipul proiectului software care urmează a fi testat (aplicație desktop, web, mobile, etc.), sau de tipul de testare automată (UI, API, Performance, DB, etc.), putem avea în vedere soluțiile HP UFT, LeanFT, Microsoft Coded UI, clasicul Selenium cu Visual Studio sau Java. Desigur că există o mulțime de alte soluții comerciale mai mult sau mai puțin cunoscute care pot fi avute în vedere, cum ar fi TestComplete, Tricentis, Ranorex, eggPlant, etc. . Criteriile principale pentru alegerea unei soluții ar fi în ordinea importanței: gratuitatea, costul licențelor, al resurselor necesare și al eventualelor traininguri, deținerea unei soluții (ducând la așa numitul sunk-cost bias sau capcana costurilor îngropate), experiența profesională în general și în particular cu soluția respectivă a celor implicați în decizie, recomandări, demo-uri și cercetare personală. Alte criterii de alegere pot fi cele ce țin de politica companiei, de colaborare, de existența suportului comercial, dar și de soluțiile impuse de către client. Deși de cele mai multe ori, marketingul și evaluările externe de tip marketing pot avea o influență hotărâtoare.
Dacă nu avem nici un fel de experiență cu soluția de testare automată respectivă, putem începe cu facilitatea "record and playback" pentru a înregistra câteva teste și a le rula, demonstrând astfel viabilitatea soluției respective. Cu toate că de cele mai multe ori această facilitate eșuează în proiectele reale, fiind mai degrabă o facilitate existentă în scop de marketing, de multe ori aceasta este utilă pentru un start rapid în faza inițială de evaluare a diferitelor soluții de testare automată.
Pentru a iniția cu succes un proiect de testare automată, sunt recomandate următoarele condiții prealabile:
Proiectul software supus testării trebuie să se afle într-o stare relativ stabilă, cu alte cuvinte să se afle mai degrabă într-o fază de dezvoltare de noi funcționalități, sau chiar în faza de întreținere. Inițierea testării automate în fazele inițiale de dezvoltare, înainte ca proiectul software să fie disponibil unor utilizatori finali, este mai degrabă o abordare riscantă, având șanse mari de anulare și rescriere a scripturilor de testare sau chiar de anulare totală a soluțiilor de testare automată în care s-au investit timp și bani.
Există un set de cazuri de testare (de obicei, de regresie) bine documentate, și care se execută manual după fiecare etapă de dezvoltare, în funcție de metodologia de dezvoltare. O parte dintre aceste cazuri de testare manuală urmează să fie automatizate.
Proiectul de testare automată a fost planificat și evaluat în mod corespunzător, ca orice alt proiect software, ținând cont de constrângerile clasice ale oricărui proiect, respectiv scopul, timpul și costurile, apoi riscurile, resursele și calitatea.
Deși sunt destul de cunoscute, merită să reamintim aici avantajele testării automate, care pot fi aduse ca argumente atunci când încercăm să influențăm decizia de a iniția un proiect de testare automată, și anume:
Automatizarea poate prelua cazurile de testare manuală, executate în mod repetat (de obicei, cele de regresie), în timp ce inginerii de testare se pot concentra pe alte teste de explorare importante sau pe alte sarcini, extinzând aria de testare.
Execuția mult mai rapidă a testelor, relevantă fiind atunci când e necesar ca problemele să fie descoperite imediat după disponibilitatea software-ului, și nu după una sau mai multe zile de testare manuală.
Dezvoltatorii pot modifica cu încredere codul deja scris, deoarece testarea automată de regresie poate fi rulată în mod continuu sau ori de câte ori este necesar.
Execuția nesupravegheată a testării, cu o raportare extensivă și detaliată, având siguranța verificării rezultatelor după execuție.
Mergând mai departe, soluția de testare automată poate fi uneori una simplă, prin simpla utilizare a uneltei de testare alese, conform recomandărilor furnizorului soluției, respectiv fără implementarea unui Framework. Dacă soluția de testare automată este mai complexă, și aceasta presupune crearea unei arhitecturi software, împreună cu unul sau mai multe Frameworkuri, pornind de la una sau mai multe soluții comerciale sau open source cunoscute, procesul în linii mari ar fi același ca în cazul dezvoltării oricărui proiect software, respectiv cerințe, arhitectură, design, implementare, integrare, testare, instalare, întreținere. Desigur că este important să se țină cont și de metodologia de dezvoltare a proiectului software supus testării. Din păcate, în proiectele reale, de multe ori se începe direct cu implementarea Frameworkului pentru testarea automată a unui software departe de a fi finalizat și astfel instabil, ignorând lipsa condițiilor prealabile exemplificate mai sus precum și trecerea peste etapele premergătoare de definire a cerințelor, arhitectură și design, insuccesul fiind astfel garantat. Ținând cont de aceste principii de mai sus, în continuare vom exemplifica o arhitectură avansată de testare automată, elegantă și modernă, bazată exclusiv pe componente open source sau gratuite pentru uzul comercial. După cum se poate vedea mai jos, această arhitectură integrează toate aceste componente, bazate pe multiple și diverse tehnologii, într-o soluție inovatoare, unică și completă, care poate satisface cerințele oricărui proiect de testare automată, în cazul de față al unui software web complex.
Următoarele componente fac parte din această arhitectură:
PyCharm Community de la compania JetBrains - un IDE open source, gratuit, pentru programarea în Python și în Robot Framework.
Python - se poate folosi cu succes atât varianta de la Python.org cât și varianta ActivePython de la compania Active State, care poate fi folosită în scop comercial în anumite condiții.
Robot Framework - un Framework generic, open source, implementat în Python, creat pentru testare automată. A fost inițial dezvoltat de către Nokia Networks, și are o comunitate foarte activă de susținători și suport tehnic. De asemenea, este sponsorizat de către fundația Robot Framework formată din mai multe companii software, în special din Finlanda.
SikuliX - open source software, implementat în Java, folosit pentru testarea automată bazată pe recunoașterea imaginilor. Algoritmul de recunoaștere a imaginilor, bazat pe OpenCV, este extrem de flexibil și fiabil, scorul de potrivire putând fi manipulat între orice valori: de exemplu, de la valoarea implicită de 0.7 până la potrivirea exactă de 1.0.
Selenium - open source software, folosit pentru automatizarea interacțiunii cu navigatoarele web. Testarea automată este bazată pe identificarea elementelor din documentele HTML, elemente ascunse utilizatorului obișnuit.
Deși există biblioteci open source disponibile în Robot Framework pentru fiecare dintre componentele SikuliX, Selenium și AutoIT, doar biblioteca Selenium este destul de avansată și folosită pe larg, astfel încât ne putem baza pe ea. Scriptul AutoIT este apelat ca proces separat din Robot Framework, deși poate fi implementată și o bibliotecă Robot Framework dacă se consideră necesar. Pentru SikuliX este recomandată implementarea unei biblioteci noi, mai degrabă decât rularea ca proces separat ale unor scripturi exclusive SikuliX. Implementarea acestor biblioteci în Robot Framework permite executarea combinată, în funcție de nevoi, a oricărei acțiuni prin intermediul celor 3 componente. De exemplu, verificarea și clickul pe un element identificat cu Selenium, apoi verificarea și clickul pe un element identificat cu SikuliX și eventual extragerea informațiilor din baza de date, de exemplu pentru login, cu ajutorul AutoIT.
Avantajele acestei soluții ar fi:
Pe lângă Selenium și SikuliX, multe alte biblioteci și pluginuri sunt disponibile pentru diferite task-uri, cum ar fi cele pentru sistemul de operare sau manipularea fișierelor.
Folosește așa numitele Keyword-driven, Data-driven și Behavior-driven pentru stilurile cazurilor de testare, aceste stiluri fiind ușor de înțeles chiar și de către alți specialiști în afara programatorilor.
Robot Framework este elegant, flexibil, personalizabil și extensibil, incluzând și raportarea rezultatelor testării automate.
Implementarea rapidă și relativ ușoară ale unor noi cazuri de testare. Inginerii se pot concentra pe designul cazurilor de testare, mai degrabă decât pe dezvoltarea codului într-un anumit limbaj de programare (cu defectele proprii inerente). Iar testarea automată nu ar trebui să fie despre dezvoltarea unui nou produs software complex (așa cum se întâmplă în foarte multe cazuri), care să fie folosit pentru testarea unui alt produs software complex, ci mai degrabă despre proiectarea și implementarea facilă a tuturor cazurilor de testare necesare, care să reflecte modul real de folosire al produsului software-ului.
Este un concept ușor de învățat, iar actualizarea ulterioară a scripturilor de testare automată este și ea facilă.
Se pot executa selectiv și relativ ușor seturi de teste bazate pe etichete (Tags) care să fie incluse/ excluse, pe bază de modul, sistem de testare sau orice alt criteriu, etc. .
Conține o interfață de executare a testelor bazată pe linia de comandă, care poate include cu ușurință diferite variabile cum ar fi timpul de așteptare personalizat pentru a obține răspunsul interfeței sau un mecanism elegant de a rula din nou, de mai multe ori, în mod manual sau automat, doar acele cazuri de testare care au eșuat la ultima execuție, caz destul de des întâlnit la execuția testelor automate.
Dezavantajele acestei soluții ar fi:
Nu funcționează "out of the box", ca în cazul soluțiilor comerciale, de exemplu Visual Studio sau UFT, adică prin instalarea unui software comercial, aducerea codului sursă dintr-un repository, compilarea și executarea testelor.
Sunt necesari mai mulți pași pentru instalarea multiplelor componente individuale și apoi pentru a implementa legăturile lipsă necesare pentru integrarea acestora într-o soluție de sine stătătoare. Pentru a ușura instalarea acestei soluții pe mașinile de testare, (de exemplu, pe mașinile altor ingineri care vor lucra cu această soluție sau pe mașinile fizice sau virtuale care vor fi folosite pentru rularea nesupravegheată a testelor automate), este recomandat ca toate aceste componente să fie configurate în așa fel încât să ruleze în modul "portabil", adică fără nici o legătură cu setările de variabile sau pathurile din sistemul de operare.
Suportul comercial nu este disponibil. Totuși este bine cunoscut faptul că suportul comunității de utilizatori este de cele mai multe ori mult mai eficient și mai rapid decât orice suport comercial, experiența arătându-ne că majoritatea problemelor tehnice fie au deja o soluție publică, fie pot obține o soluție din partea comunității de utilizatori.
Deși utilizarea diferitelor componente open source sau gratuite pentru uzul comercial este exemplificată în detaliu în diferite articole, bloguri sau pe site-urile oficiale de distribuție ale componentelor, integrarea completă și funcțională ale tuturor componentelor în arhitectura prezentată mai sus poate fi considerată dificilă. Deși nu este o descriere completă, pentru a înțelege în mare cum a fost construită și integrată aceasta arhitectură, pașii ar fi următorii:
Se instalează Python27, robotframework, robotframework-selenium2library, PyCharm, plugin-ul Robot Framework Support pentru PyCharm, SixuliX, jython2.7.0, autoit-v3, KeePass-2.35, și driverele Selenium (chromedriver, geckodriver, IEDriverServer).
Dacă se dorește o configurație "portabilă", toate aceste componente se instalează în același path de bază sau pe un Virtual Hard Disk, asigurând configurările necesare astfel încât toate componentele să ruleze în modul "portabil", folosind pathuri relative, respectiv orice legătură cu sistemul de operare cu privire la path-uri sau variabile de sistem trebuind înlăturată.
class SikuliRemoteLib(BaseLogger):
def __init__(self):
self.appRegion=Region()
..
def click_object(self,img,offsetX=0,offsetY=0):
self._find_object(img,offsetX,offsetY)
self.appRegion.click(self.appPattern)
...
care va conține toate keywordurile necesare a fi apelate din Robot Framework, sub forma unor funcții care să apeleze funcțiile din SikuliX prin intermediul jython, și apoi instanțierea acestei clase în main:
if __name__ == '__main__':
import sys
from robotremoteserver import RobotRemoteServer
RobotRemoteServer(SikuliRemoteLib(),
*sys.argv[1:])
Moștenirea din BaseLogger permite în plus personalizarea logurilor, pentru ca acestea să conțină atât imaginea de referință cât și imaginea reală cu care se compară, pentru mai multă siguranță la verificarea rezultatelor execuției testelor, cât și pentru corectarea ulterioară a unor imagini de referință.
4.Serverele SikuliX și Selenium se pot porni în mod automat din Robot Framework, folosind fișierul special init.robot, care poate conține următoarele linii de cod:
Resource ${CURDIR}/Common/sikuliremote.robot
Suite Setup Start And Import Remote Library SikuliRemoteLib/sikuliremotelib.py
Suite Teardown Stop Remote Library ${True}
Iar Start And Import Remote Library conține codul prin care se pornește SikuliX prin procesul java jython.jar, precum și Selenium, de exemplu pentru chromedriver.
Mai multe detalii pentru această procedură se pot explora în documentația Robot Framework precum și direct în codul sursă de pe Git.
Având toată această arhitectură integrată, nu ne rămâne decât să creăm proiectul final, structurat pe module în funcție de specificul aplicației, să decidem locația imaginilor de referință și să realizăm primul fișier de tipul robot cu primele teste.
Presupunând că dorim să implementam un test de regresie pentru profilul de utilizator Facebook, instrucțiunile de testare, folosind Visual Studio cu Selenium, ar fi următoarele:
[Test]
public void FbTest()
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.Navigate().GoToUrl(
"https://www.facebook.com");
// 1. Assume new browser profile,
// thus logon required all the time
wait.Until(ExpectedConditions.
ElementIsVisible(By.Id("email")));
// hardcoded here for demo only, otherwise would
// call a keyword that will use KeePass instead
driver.FindElement(By.Id("email"))
.SendKeys("username");
driver.FindElement(By.Id("pass"))
.SendKeys("password");
driver.FindElement(By.Id("loginbutton")).Click();
// 2. Close notification dialog if appearing
IWebElement element = IsElementPresent(
By.XPath(
"//*[@aria-labelledby='notification-permission-title']//a"));
if (element != null)
element.Click();
// 3. Check if FB logo and search field are displayed correctly
driver.FindElement(By.XPath(
"//*[@data-testid='blue_bar_fb_logo']"));
driver.FindElement(By.XPath(
"//*[@data-testid='search_input']"));
// 4. Click on user name to display user profile
driver.FindElement(By.XPath(
"//*[@id='u_0_4']/div[1]/div[1]/div/a/span"))
.Click();
// Check the Profile Picture element exists
driver.FindElement(By.XPath(
"//*[@class='profilePicThumb']"));
// 5. Check the tabs Timeline,
// Friends and Photos exist
driver.FindElement(By.XPath(
"//*[@data-tab-key='timeline']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='friends']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='photos']"));
// 6. Check the tab More exists,
// click it in order to activate popup items
driver.FindElement(By.XPath(
"//*[@id='fbProfileCover']/div[2]/div[2]/ul/
li[5]/div/a")).Click();
// Check if the popup items exist
driver.FindElement(By.XPath(
"//*[@data-tab-key='map']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='sports']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='books']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='likes']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='events']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='fitness']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='reviews']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='groups']"));
driver.FindElement(By.XPath(
"//*[@data-tab-key='notes']"));
// 7. Check and click on About tab
driver.FindElement(By.XPath(
"//*[@data-tab-key='about']")).Click();
// Check if the About menu is displayed correctly
driver.FindElement(By.XPath(
"//*[@id='medley_header_about']/a"));
// Several checks still missing, e.g. is the
// About tab selected and with black color while
// the other tabs are blue?
// Or, are the menu items displayed correctly in
// English language?
// ...
Instrucțiunile în limbaj Robot Framework, ar fi următoarele:
Basic FB check
[Documentation] Test Fb login, profile picture, main tabs and click on About tab
[Tags] Warmup Fb
go to https://www.facebook.com
# 1. Assume new browser profile, thus logon required
# all the time
wait until element is visible id=email
# hardcoded here for demo only, otherwise would
# call a keyword that will use KeePass instead
press key id=email username
press key id=pass password
click button //*[@id='loginbutton']/input
# 2. Close notification dialog if appearing
Run Keyword And Ignore Error click element
//*[@aria-labelledby=
// 'notification-permission-title']//a
# "T01-1 fb logo and search" and upcoming are .PNG
# files, taken as reference images on a very specific
# region
# The next used keywords are Python functions
# implemented in SikuliRemoteLib, that in turn are
# calling SikuliX methods for finding and executing
# actions on images, then logging the results.
# The numbers are x, y click coordinates, exactly
# as seen e.g. on Paint application.
# 3. Check if FB logo and search field are displayed
# correctly
wait for object T01-1 fb logo and search
# 4. Click on user name to display user profile
verify and click object T01-2 main controls
${-20} ${18}
# Check the Profile Picture element exists
wait until element is visible //*[@class='profilePicThumb']
# 6. Check the tab More exists, hover mouse over it
# in order to activate popup items
hover over object T01-3 timeline tab
${382} ${18}
# Check if the popup items exist
verify object T01-4 more popup menu
hover mouse right ${100}
# 5. Check the tabs Timeline, Friends and Photos
# elements exist
# 7. Check and click on About tab
verify and click object T01-3 timeline tab
${116} ${18}
# check the About tab is displayed correctly
verify object T01-5 about tab
# Check if the About menu is displayed correctly
verify object T01-6 about menu displayed
# No more checks are missing for this basic test.
# About tab is selected correctly and with the
# correct colors displayed
# All menu items are displayed correctly in
# English language, as in the reference image
După cum se poate vedea mai sus, instrucțiunile în Robot Framework sunt mult mai elegante și mai naturale, implementarea unui caz de testare fiind mult mai accesibilă chiar și pentru un inginer de testare fără experiență în programare pentru că logica acestor teste urmărește destul de aproape pașii din testul manual, spre deosebire de implementarea în C# și Selenium, unde cunoștințele de programare sunt obligatorii. Mai mult decât atât, timpul de scriere al unui caz de testare automat, relativ complex, este mult mai mic atunci când se folosește testarea automată bazată pe recunoașterea imaginilor, de exemplu, cu SikuliX, decât atunci când se folosește recunoașterea elementelor ascunse în pagina web ca în cazul Selenium. Concret, dacă un caz de testare în Selenium cu Visual Studio ar necesita 10 "man days", același caz de testare cu arhitectura prezentată mai sus poate fi finalizat cel mult în 1 "man day", deci de 10 ori mai repede sau cu 10% din resurse.
În concluzie, indiferent dacă criteriile de alegere a unei soluții de testare automată pun costul soluției pe un loc principal sau secundar, atunci când suntem dispuși să renunțam la varianta evidentă, populară, comercială și care beneficiază de marketing din plin și decidem să acordăm o șansă soluțiilor alternative, putem avea surpriza să obținem o soluție de testare automată nu doar gratuită, ci una cu mult mai puternică, mai elegantă și mai flexibilă pentru proiectul software care urmează a fi testat automat, atât în beneficiul membrilor echipei care vor lucra în acel proiect, cât mai ales în beneficiul clientului final al cărui produs software urmează a fi testat.
de Robert Mălai
de Dan Colceriu