Testarea Sistemelor Distribuite Bazate pe Tehnologia Internet
Cuprins:
Capitolul 1 – Introducere
Testarea – etapă a ciclului de dezvoltare software
Capitolul 2 – Tehnici de testare
Testarea unui modul
Testarea de integrare
Testarea functionala.
Testarea de validare
Capitolul 3 – Testarea sistemelor distribuite bazate pe tehnologia Internet
Componentele unui sistem distribuit
Modele de organizare a aplicațiilor distribuite
Modele arhitecturale specifice
Modelele calcului distribuit
Modelul Client Sever
Avantajele sistemelor distribuite
Testarea sistemelor distribuite bazate pe componente
Capitolul 4 – Testarea automată
De ce este testarea automată atât de importantă pentru companii?
Testarea Manuala vs Testarea Automată
Capitolul 5 – Aplicatie
BIBLIOGRAFIE
Capitolul 1 – Introducere
Testarea este activitatea de concepie a cazurilor de test, de execuie a testelor i de evaluare a rezultatelor testelor, n diferite etape ale ciclului de via al programelor.
Testarea reprezintă o etapă importantă în procesul de realizare a produselor software. Ponderea cheltuielilor cu testarea reprezintă între 30% și 50% din totalul cheltuielilor pentru dezvoltarea unei aplicații software.
Tehnicile și metodele moderne de elaborare a produselor software acordă o importanță deosebită efortului de înlăturare a erorilor de analiză, proiectare și programare prin folosirea unor mijloace evoluate de testare.
Aceasta lucrare prezintă procesul de testare, tehnicile și metodele de testare specifice aplicațiilor software. Sunt avute în vedere aplicațiile clasice, aplicațiile realizate utilizând tehnologii orientate obiect și aplicațiile distribuite. În lucrare sunt făcute referiri la utilizarea tehnicilor de testare pentru clientul de email Gmail
Un test const n execuia programului pentru un set de date de intrare convenabil ales, pentru a verifica dac rezultatul obinut este corect.
Un caz de test este un set de date de intrare mpreun cu datele de ieire pe care programul ar trebui s le produc. De exemplu, valorile coeficienilor a,b,c ai unei ecuaii de gradul doi mpreun cu valorile x1, x2, n testul unui program de rezolvare a ecuaiilor de gradul doi. Cazurile de test se aleg astfel nct s fie puse n eviden, dac este posibil, situaiile de funcionare necorespunztoare.
Prin testare nu se poate demonstra corectitudinea unui program. Aceasta deoarece n cele mai multe cazuri este practic imposibil s se testeze programul pentru toate seturile de date de intrare care pot conduce la execuii diferite ale programului. Testarea poate doar s demonstreze prezena erorilor ntr-un program. ntr-un sens, testarea este un proces distructiv, deoarece urmrete s determine o comportare a programului neintenionat de proiectani sau implementatori. Din acest punct de vedere testarea nu trebuie s fie fcut de persoanele care au contribuit la dezvoltarea programului. Pe de alt parte conoaterea structurii programului și a codului poate fi foarte utila pentru alegerea unor date de test relevante.
Testarea – etapă a ciclului de dezvoltare software
Proiectarea aplicațiilor software de dimensiuni mari, dezvoltată în cadrul unei echipe, nu se face trecând direct la implementarea programului, ci urmează etape bine stabilite. Procesul de dezvoltare al aplicațiilor software este alcătuit din următoarele etape: specificarea cerințelor, analiză, proiectare, implementare, testare și întreținere. În figura 2.1 este prezentat grafic modelul clasic de dezvoltare software .
Figura 1.1. – Modelul clasic de dezvoltare software
Conform figurii 1.1, în etapa de specificare a cerințelor se determină necesitățile pentru toate elementele sistemului, atât hardware cât și software. Testarea specificațiilor se realizează prin metode de analiză statică: inspecții, parcurgeri și analize tehnice.
Etapa de analiză continuă procesul de stabilire a cerințelor. Analistul trebuie să înțeleagă domeniul informațiilor pentru software, funcțiile necesare, performanțele și interfețele. Se documentează cerințele, iar acestea sunt revăzute împreună cu beneficiarul. În această etapă este descris ceea ce trebuie să facă aplicația informatică și nu modul în care se realizează. în testarea unei aplicații sunt definite principalele caracteristici ale aplicațiilor componente: magazin electronic, gestiunea bibliotecii, bugetul personal, agenda telefonică, rețete culinare și jurnalul personal. Sunt descrise cazurile de test pentru fiecare componentă în parte.
În etapa de proiectare accentul se pune pe structurile de date, arhitectura sistemului, detaliile procedurale și caracterizarea interfețelor. În această etapă sunt identificate structurile de date, interfețele, modulele și sunt descriși algoritmii. Pentru fiecare modul în parte sunt definite specificațiile de realizare. Cazurile de test sunt rafinate și sunt adăugate noi cazuri de test corespunzătoare detaliilor introduse. Statistic peste 35% din erorile software își au originea în fazele de analiză și proiectare.
Prin implementare se face trecerea de la proiect la o formă specifică mașinii de calcul. Implementarea este cu atât mai ușor de realizat cu cât proiectarea se realizează mai în detaliu. Testarea în etapa de implementare are rolul de a evidenția diferențele dintre comportamentul produsului din specificații și cel dat la nivelul utilizatorilor. Testarea se concentrează atât asupra logicii interne a programului, avându-se în vedere ca anumite elemente ale acestuia să fie parcurse, cât și pe funcționalitatea externă a sa, pe baza specificațiilor. Se compară rezultatele efective obținute după rularea programului cu seturi de date de test cu rezultatele scontate pe baza specificațiilor.
În timp, după livrarea la beneficiar, aplicațiile software suferă schimbări care se datorează erorilor descoperite pe parcursul funcționării aplicației, modificărilor mediului în care rulează aplicația (software, hardware) precum și noilor cerințe de performanță și funcționalitate dorite de beneficiar. Întreținerea aplicațiilor software se aplică tuturor fazelor ciclului de viață.
În cadrul ciclului de dezvoltare software, un rol important îl au verificarea și validarea (V & V). Verificarea și validarea reprezintă un proces prin care se determină dacă cerințele unui sistem sau componentă sunt complete și corecte, dacă rezultatul fiecărei faze de dezvoltare îndeplinește cerințele sau condițiile impuse în faza anterioară și dacă sistemul sau componenta finală este în concordanță cu cerințele specificate.
Verificarea este mulțimea activităților care asigură că o aplicație software implementează corect o anumită funcție. Testarea software este o componentă a procesului de V & V.
Validarea este mulțimea activităților care asigură că o aplicație software realizată este în concordanță cu cerințele beneficiarului. Pe măsura dezvoltării incrementale a aplciatiei rezultatele din fazele intermediare sunt validate de către client.
Testarea sau analiza statică are ca scop examinarea aplicațiilor software fără a fi executate și cuprinde activități precum inspecțiile, execuția simbolică și verificarea. Aceste activități fac parte din categoria evaluările tehnice.
Inspecțiile codului presupun citirea sau inspecția vizuală a codului sursă de către un grup de persoane. Având la dispoziție codul sursă și specificațiile de proiectare, grupul de persoane din echipa de inspecție urmărește explicațiile programatorului legate de logica programului, instrucțiune cu instrucțiune. În acest mod se descoperă o serie de erori specifice acestei metode cum ar fi: declararea datelor, referirea datelor, erorile de calcul, erorile de comparare, erorile de logică, erorile de intrare/ieșire, erorile de interfață etc.
Parcurgerile constau în citirea sau inspecția vizuală a codului sursă de către un grup de persoane, însă procedura de lucru este diferită având ca scop execuția logică a fiecărei secvențe de cod de testat pe baza unor seturi de test pregătite anterior. Prin urmărirea programului pas cu pas sunt identificate erori care apar la acest nivel. Rezultatele acestei activități de verificare depind, ca și în cazul inspecțiilor codului, de atitudinea echipei față de persoana care a scris programul, având în vedere faptul că atenția trebuie acordată programului care se verifică și nu celui care l-a scris.
Verificarea de birou este o tehnică de analiză statică în care listingurile codurilor sau rezultatele testelor sau alte documente sunt examinate vizual, de obicei de persoana care le-a realizat, pentru a identifica erorile sau abaterile de la standardele de dezvoltare sau alte probleme.
Testarea dinamică presupune examinarea aplicațiilor software în scopul generării datelor de test cu care acestea vor fi executate și rularea aplicațiilor cu seturile de date de test obținute. Se observă că spre deosebire de testarea statică, testarea dinamică presupune execuția aplicației care se testează. Există două strategii de dezvoltare a cazurilor de test: o strategie bazată pe structura programelor și o alta, bazată pe funcționalitatea acestora.
În dezvoltarea unui produs software testarea se realizează pe mai multe niveluri: testarea de module, testarea de integrare, testarea de sistem și testarea de acceptare (validare). În figura 2.2 este prezentat procesul de verificare și validare în cadrul ciclului de dezvoltare a unui produs software. Se identifică etapele de realizare a aplicației precum și etapele și nivelurile procesului de testare software.
Figura 1.2. – Testarea software în ciclul de dezvoltare
Capitolul 2 – Tehnici de testare
Sunt doua clase mari din care fac parte tehnicile de testare. Pentru a intelege diferenta dintre cele doua vom defini fiecare clasa în cele ce urmeaza:
Testarea Black Box – cunoscuta si ca testare functionala, e testarea care ignora mecanismele interne ale unui sistem sau a unei componente si se axeaza doar pe datele de iesire generate ca raspuns a datelor de intrare si a conditiilor de executare a testelor
Testarea White Box – numita si testare structurala, este testarea care se face în interiorul unui sistem sau a unei componente.
Cele doua clase de testare sunt date practic de opacitatea codului sursa fata de testeri.
Mai exact, în cazul testarii Black Box testerul nu are acces deloc la codul sursa. Codul este considerat ca o cutie neagra în interiorul careia nu se poate vedea. Se stiu doar ce date de intrare poate avea sistemul sau componenta si ca va obtine niste date de iesire. Bazat pe cerintele produsului, testerul stie ce rezultate de iesire ar trebui sa obina de la sistem sau componenta.
De cealalta parte testarea White Box se axeaza pe structura interna a codului. Testerul care face testarea White Box, în general chiar programatorul, stie cum arata codul si va scrie cazuri de test care executa metode sau functii cu anumiti parametrii, în limbajul modelului V&V, testarea black box este utilizata deseori pentru validare, pentru a ne asigura ca se construieste aplicatia corecta, conform cerintelor, iar testarea white box este folosita pentru verificare, pentru a ne asigura ca aplicatia este correct implementata.
Sunt cateva tipuri de testare care ar trebui aplicate pe un sistem software. Fiecare tip are specificatiile lui care defineste corectitudnea comportamentului în functie de care poate fi idnetificat comportamentul incorect. Tipurile si specificatiile, la ce se na uitam cand cream testele, vor fi detaliate în cele ce urmeaza.
Testarea unui modul (o funcie, o clas, unitate Pascal, un pachet ADA, etc.) este realizat de programatorul care implementeaz modulul. Toate celelalte teste sunt efectuate, n general, de persoane care nu au participat la dezvoltarea programului.
Scopul testarii unui modul este de a se stabili ca modulul este o implementare corecta a specificatiei sale (conforma cu specificatia sa). Specificatia poate fi neformala sau formala
In cursul testarii unui modul, modulul este tratat ca o entitate independent, care nu necesit prezena altor componednea comportamentului în functie de care poate fi idnetificat comportamentul incorect. Tipurile si specificatiile, la ce se na uitam cand cream testele, vor fi detaliate în cele ce urmeaza.
Testarea unui modul (o funcie, o clas, unitate Pascal, un pachet ADA, etc.) este realizat de programatorul care implementeaz modulul. Toate celelalte teste sunt efectuate, n general, de persoane care nu au participat la dezvoltarea programului.
Scopul testarii unui modul este de a se stabili ca modulul este o implementare corecta a specificatiei sale (conforma cu specificatia sa). Specificatia poate fi neformala sau formala
In cursul testarii unui modul, modulul este tratat ca o entitate independent, care nu necesit prezena altor componente ale programului. Testarea izolat a unui modul ridic dou probleme:
simularea modulelor apelate de cel testat;
simularea modulelor apelante.
Modulele prin care se simuleaz modulele apelate de modulul testat se numesc module "ciot" (n englez, "stub") . Un modul "ciot" are aceeai interfa cu modulul testat i realizeaz n mod simplificat funcia sa.
Un modul "ciot" se poate reduce eventual la o tabel de perechi de forma: "valori ale parametrilor de intrare la un apel – rezultatul prevzut".
Cazurile de apel ale modulului testat de ctre celelalte module ale programului sunt simulate n cadrul unui "modul driver". Modulul driver apeleaz modulul testat furnizndu-i ca date de intrare datele de test ale modulului. Datele de test pot fi generate de modulul driver, pot fi preluate dintr-un fiier sau furnizate de testor ntr-o manier interactiv.
Figura 2.1. – Structura programului executabil pentru testarea izolata a unui modul.
Testele de integrare
Sunt dedicate verificrii interaciunilor dintre module, grupuri de module, subsisteme, pn la nivel de sistem. Exist mai multe metode de realizare a testelor de integrare.
Testele de integrare presupun, ca i testele unitare, realizarea de module "ciot" i module "driver". Numrul de module "driver" i de module "ciot" necesare n testele de integrare depinde de ordinea n care sunt testate modulele (metoda de integrare). Testele de integrare necesit de asemenea instrumente de gestiune a versiunilor i a configuraiilor.
Metoda "big-bang"
Sunt integrate ntr-un program executabil toate modulele existente la un moment dat. Modulele "driver" i "ciot" necesare sunt de asemenea integrate. Metoda este periculoas cci toate erorile apar n acelai timp i localizarea lor este dificil.
Integrare progresiva
Metodele de integrare progresiv sunt mult mai eficiente. în fiecare moment se adaug ansamblului de module integrate numai un singur modul. Astfel, erorile care apar la un test provin din modulul care a fost ultimul integrat.
Integrarea ascendent ("de jos n sus")
Se ncepe prin testarea modulelor care nu apeleaz alte module, apoi se adaug progresiv module care apeleaz numai modulele deja testate, pn cnd este asamblat ntregul sistem. Metoda necesit implementarea cte unui modul "driver" pentru fiecare modul al programului (i nici un modul "ciot").
Avantajele testrii de jos n sus
Nu sunt necesare module "ciot". Modulele "driver" se implementeaz mult mai uor dect modulele "ciot". Exist chiar instrumente care produc automat module "driver".
Dezavantajele testrii de jos n sus
1. Programul pe baza cruia se efectueaz validarea cerinelor este disponibil numai dup testarea ultimului modul.
2. Corectarea erorilor descoperite pe parcursul integrrii necesit repetarea procesului de proiectare, codificare i testare a modulelor. Principalele erori de proiectare sunt descoperite de abia la sfârit, cnd sunt testate modulele principale ale programului. ceea ce, n general, conduce la reproiectare i reimplementare.
Integrarea descendent ("de sus n jos")
Se ncepe prin testarea modulului principal, apoi se testeaz programul obinut prin integrarea modulului principal i a modulelor direct apelate de el, i aa mai departe. Metoda presupune implementarea unui singur modul "driver" (pentru modulul principal) i a cte unui modul "ciot" pentru fiecare alt modul al programului.
Integrarea descendent poate avea loc pe parcursul unei implementri descendente a programului. Modulul principal este testat imediat ce a fost implementat, moment n care nu au fost nc implementate modulele apelate de el. De aceea, pentru testare este necesar s se implementeze module "ciot". în continuare, pe msur ce se implementeaz modulele de pe nivelul ierarhic inferior, se trece la testarea lor folosind alte module “ciot”, .a.m.d. în fiecare pas este nlocuit un singur modul "ciot" cu cel real.
Avantajele testrii de sus n jos
Erorile de proiectare sunt descoperite timpuriu, la inceputul procesului de integrare, atunci când sunt testate modulele principale ale programului. Aceste erori fiind corectate la nceput, se evit reproiectarea i reimplementarea majoritii componentelor de nivel mai coborât, aa cum se ntâmpl cnd erorile respective sunt descoperite la sfâritul procesului de integrare.
Programul obtinut este mai fiabil caci principalele module sunt cel
mai mult testate.
3. Prin testarea modulelor de nivel superior se poate considera c sistemul n ansamblul su exist dintr-o faza timpurie a dezvoltrii i deci se poate exersa cu el n vederea validrii cerinelor; acest aspect este de asemenea, foarte important n privina costului dezvoltrii sistemului.
Dezavantajele testrii de sus n jos
1. Este necesar s se implementeze cte un modul "ciot" pentru fiecare modul al programului, cu excepia modulului principal.
2. Este dificil de simulat prin module "ciot" componente complexe i componente care conin n interfa structuri de date.
3. n testarea componentelor de pe primele nivele, care de regul nu afieaz rezultate, este necesar s se introduc instruciuni de afiare, care apoi sunt extrase, ceea ce presupune o nou testare a modulelor.
Aceste dezavantaje pot fi reduse aplicand tehnici hibride, de exemplu, folosind n locul unor module "ciot", direct modulele reale testate. Integrarea nu trebuie să fie strict descendenta. De exemplu, experienta arata ca este foarte util să se nceapa prin integrarea modulelor de interfa utilizator. Aceasta permite continuarea integrrii n condiii mai bune de observare a comportrii programului.
Testarea funcțională
Testarea funcțională este o strategie de testare care necesită cunoașterea comportamentului extern al programului pe baza specificațiilor. Testarea funcțională nu necesită cunoașterea structurii interne a programului sau cunoștințe despre modul în care este implementat programul sau modulul.
Principalele tehnici de testare funcțională sunt testarea cu intrări aleatoare, partiționarea pe clase de echivalențe, analiza valorilor limită, graful cauză-efect și ghicirea erorilor.
Testarea cu intrări aleatoare pornește de la domeniul datelor de intrare și constă în generarea de date de test în mod aleator, în cadrul domeniului acestora. Este o tehnică slabă de testare, cu cel mai mic procent de descoperire a erorilor. Această tehnică de testare a fost dezvoltată, astfel încât datele de test sunt alese aleatoriu din domeniu și sunt filtrate astfel încât să îndeplinească anumite condiții, ca de exemplu producerea unui rezultat dintr-o clasă de ieșiri posibile.
Partiționarea pe clase de echivalențe constă în împărțirea domeniului datelor de intrare în subdomenii, astfel încât comportamentul programului să fie același, cel puțin teoretic, pentru orice dată de intrare din subdomeniul corespunzător. De exemplu, pentru funcția care returnează valoare absolută a unui număr întreg, un subdomeniu ar fi intervalul numerelor strict negative, iar un alt subdomeniu ar fi cel al numerelor pozitive. Dintr-un număr ridicat de cazuri de test posibile se ajunge la două cazuri de test.
Caracteristicile partiționării pe clase de echivalențe sunt:
• domeniul datelor de intrare este împărțit în clase de echivalențe;
• elementele din aceeași clasă sunt tratate în mod asemănător;
• de asemenea se are în vedere partiționarea ieșirilor;
• se consideră atât clasele valide cât și cele invalide;
• pentru testare se alege cel puțin un element din fiecare clasă de echivalență.
Prin utilizarea analizei valorilor limită pentru realizarea cazurilor de test, pentru fiecare parametru al funcției se determină un set de valori aflate la limita domeniul de validitate. Analiza valorilor limită se concentrează asupra valorilor de la limita claselor de echivalențe și sunt avute în vedere limitele atât în spațiul intrărilor cât și în spațiul ieșirilor.
Dacă li este limita inferioară și ls este limita superioară a domeniului unei date de intrare de tip numeric, pentru aceasta se vor construi următoarele cazuri de test: li-1, li, li+1, ls-1, ls și ls+1.
Testarea de validare
Are loc după ce toate erorile de interfață descoperite în cadrul testării de integrare au fost corectate. Testarea de validare se încheie cu succes atunci când funcționalitatea aplicației software este în conformitate cu cerințele beneficiaru lui. Pentru testarea de validare se utilizează o serie de teste funcționale pentru a confirma faptul că aplicația software se comportă conform cerințelor.
În cadrul testării de validare se regăsesc testările alfa și beta. Testarea alfa este realizată la firma care produce aplicația software, beneficiarul fiind acela care conduce testele. Testarea beta este realizată la beneficiari și utilizatori finali. Aceștia primesc o versiune a aplicației software, versiune apropiată de cea finală și o utilizează în scopul descoperirii erorilor și a problemelor de performanță și funcționalitate. Problemele apărute în cadrul acestei testări sunt raportate firmei care a realizat aplicația. După ce perioada acordată pentru testarea beta s-a termina t, toate erorile apărute sunt corectate, urmând să se realizeze versiunea finală a aplicației software.
După ce a avut loc testarea aplicației software, intervine testarea de sistem, prin care se testează întregul sistem în care produsul software este o parte componentă a acestuia. Testarea de sistem presupune rularea unor teste diferite, astfel încât să fie examinate toate caracteristicile sistemului.
În literatura de specialitate, sunt prezentate câteva tehnici specifice pentru testarea de sistem. Astfel, se identifică testarea pentru determinarea capacității de recuperare (recovery testing), testarea securității, testarea de solicitare (stress testing), testarea de încărcare (load testing) și testarea performanțelor (performance testing).
Testarea pentru determinarea capacității de recuperare este un test de sistem care, printr-o multitudine de căi, forțează aplicația software să își încheie execuția în mod necorespunzător. Prin acestea se testează capacitatea aplicației de revenire dintr-o situație necorespunzătoare.
Testarea securității se realizează pentru a verifica eficiența mecanismelor de protecție dintr-un sistem software și dacă acesta se comportă corespunzător la atacurile externe.
Testarea de solicitare se execută astfel încât sistemul să funcționeze cu un volum mai mare de resurse decât cel normal, cu scopul de a determina fiabilitatea aplicației și momentul în care funcționarea aplicației devine critică și pentru a lua măsurile corespunzătoare, astfel încât să nu se ajungă în exploatarea de zi cu zi a sistemului informatic la astfel de situații. Utilizând instrumente care simulează existența mai multor utilizatori simultan, precum JMeter și Rational SiteCheck,
Testarea de încărcare constă în rularea sistemului software în condițiile în care resursele (memorie, microprocesor, rețea) sunt încărcate la maxim astfel încât se ajunge la situații critice, în care o parte din resurse nu mai sunt disponibile. Se urmărește capacitatea sistemului de a-și întrerupe funcționarea fără pierderea sau coruperea datelor.
Testarea performantelor se realizează pentru determinarea confirmitătii sistemului cu cerintele de performanta impuse. De exemplu sistemul este incărcat într-un interval de timp pornind de la capacitatea minima pana la capacitatea maxima și se verifica daca resursele sistemului se afla în limitele corespunzatoare și nu sunt intarzieri în executarea funcțiilor aplicației.
Fazele procesului de testare software
Fazele procesului de testare sunt: planificarea, analiza și proiectarea, implementarea și execuția și evaluarea testelor.
Planificarea testelor se realizează în strânsă legătură cu planificarea derulării proiectului. În faza de planificare a proiectului pentru testare se alocă resurse, specificându-se bugetul și perioada de timp în care se va derula testarea. Pe baza acestora se realizează planificarea detaliată a procesului de testare.
Planificarea testării are scopul de a determina ce să testeze și cât să testeze, astfel încât procesul de testare să se încadreze în limitele resurselor alocate. În urma planificării testării rezultă planul de test, un document pe baza căruia se desfășoară celelalte faze ale testării. În această fază se identifică și obiectivele testării.
Planul de test este un document important, fiind utilizat ca bază pentru desfășurarea întregului proces de testare. În plus, trebuie identificate și sursele de risc în testare. Planificarea testării poate să înceapă din momentul în care au fost elaborate cerințele aplicației software . În planul de test sunt descrise:
• aria de cuprindere;
• responsabilitățile fiecărui membru al echipei de testare;
• resursele umane necesare;
• desfășurarea în timp a testelor;
• descrierea și configurarea mediului specific aplicației;
• lista echipamentelor care trebuie achiziționate;
• crearea și managementul datelor de test;
• criteriile de acceptare a testelor.
Deoarece este foarte dificil să se stabilească momentul în care se va încheia testarea, în planul de test se specifică o serie de criterii care constituie o bază pentru determinarea finalizării testării.
Analiza testelor rafinează metodele prezentate în planul de test.
Sunt prezentate etapele fazelor de analiză și proiectare a testelor.
Astfel, în etapa de analiză se identifică următorii pași:
• identificarea scopurilor, obiectivelor și a strategilor testării de către echipa de testare;
• metodele de verificare sunt asociate cerințelor sistemului sau cazurilor de utilizare și sunt documentate în cadrul unei matrice de urmărire a cerințelor;
• analiza cerințelor testelor;
• construirea matricei cerințelor testelor, în care declarațiile cerințelor testelor sunt asociate cerințelor sistemului sau a cazurilor de utilizare;
• asocierea tehnicilor de testare cu declarațiile cerințelor testelor.
În faza de analiză a procesului de testare, un aspect important îl ocupă analiza cerințelor pentru testare. Cerințele testării trebuie să fie identificate și documentate astfel încât toate persoanele implicate în procesul de testare să fie conștiente de scopul acestuia. Analiza se desfășoară din mai multe puncte de vedere, depinzând de faza de testare. Astfel se identifică o abordare structurală și o abordare bazată pe comportament.
Faza de proiectare a testelor urmează după încheierea analizei. În faza de proiectare, apar următorii pași:
• definirea modelului programului de test astfel încât acesta să
reflecte tehnicile de testare utilizate;
• definirea arhitecturii de test;
• definirea procedurilor de test;
• luarea deciziei de automatizare a anumitor teste și de testare manuală a altor componente;
• asocierea datelor de test astfel încât fiecare cerință pentru datele de test să se reflecte pentru fiecare procedură de test.
Programul de test se elaborează fie la nivelul proiectării, fie la nivelul tehnicilor de testare. În primul caz, procedurile de test sunt asociate componentelor hardware și software ale aplicației, iar în al doilea caz procedurile de testare sunt văzute la nivelul tehnicilor de testare.Proiectarea procedurilor de test începe după determinarea cerințelor testării. Proiectarea procedurilor de test constă în:
• analiza arhitecturii de test pentru determinarea tehnicilor de testare relevante;
• definirea procedurilor de test atât la nivelul sistemului cât și la nivelul de implementare;
• elaborarea sau preluarea de standarde de utilizare a procedurilor de test;
• identificarea procedurilor de test care vor fi efectuate manual și a celor care vor fi efectuate automat;
• identificarea procedurilor de test complexe, pentru a fi proiectate în continuare în faza de proiectare detaliată;
• proiectarea detaliată.
În etapa de implementare a testelor sunt construite cazurile de test și procedurile de test, pe baza rezultatelor fazei de proiectare. Cazurile de test descriu atât parametrii de intrare cât și rezultatele așteptate după execuție utilizând acei parametri. Realizarea de cazuri de test cât mai complete duce la descoperirea unui număr mai mare de erori. Procedurile de test identifică toți pașii necesari pentru executarea cazurilor de test specifice.
Primul pas în faza de implementare este inițializarea mediului de implementare prin punerea la punct a arhitecturii dezvoltării testelor.
Un alt aspect important este identificarea standardelor pe care se bazează elaborarea secvențelor de test. Dacă au fost definite astfel de standarde de implementare, atunci implementarea se realizează pe baza acestora. Dacă nu există standarde, în cadrul acestei faze, la început, se stabilesc convenții de scriere a programelor de test (alinieri, comentarii, prefixe pentru date).
Implementarea secvențelor de test se realizează în limbaje specifice mediilor de testare (asemănătoare Visual Basic) sau se utilizează limbaje de programare evoluate (C++, Java).
Prin reutilizare se folosesc proceduri de test din proiectele anterioare sau din cadrul aceluiași proiect pentru module care au părți comune. În [McGR97c], [McGR97d] este prezentată o arhitectură paralelă de testare a claselor, în care clasele de test sunt derivate în paralel cu dezvoltarea ierarhiei claselor care se testează.
Faza de rulare a testelor are ca intrări planul de test și orarul execuției procedurilor de test, mediul de test fiind pregătit corespunzător. Ieșirile fazei de execuție a testelor sunt rezultatele testelor, lecțiile învățate și orarul modificat al testelor. Execuția modulelor se realizează în conformitate cu planul de test. Procedurile de test descriu intrările și ieșirile așteptate după execuție.
În această etapă din cadrul procesului de testare sunt rulate secvențele de test. Execuția secvențelor de test se realizează pe cât posibil în mediul specific aplicației iar dacă nu este posibil, acest mediu este simulat.
Rezultatele execuției secvențelor de test sunt evaluate pentru a determina dacă produsul a trecut testul cu succes. Evaluarea rezultatelor testelor se face de către un oracol. Oracolul este o persoană sau un instrument automat, care pe baza specificațiilor determină dacă rezultatele execuției testelor sunt corecte sau nu.
În figura 2.2. este prezentat fluxul procesului de execuție și evaluare a testelor pentru testarea la nivel de modul, bazată pe specificații. Rezultatele testelor arată dacă programul a trecut sau nu testul.
Figura 2.2. – Fazele de executie și evaluare pentru testarea de module
Rezultatele execuției testelor se vor memora într-o bază de date care conține și alte informații referitoare la aplicația software realizată.
Execuția și evaluarea testării de integrare necesită noi secvențe de test pe rul structurii programului care sestează. Aprobarea de către beneficiar a rapoartelor testării de modul și ale testarii de integritate continue inchiierea acestor faze.
. În execuția și evaluarea testării de sistem, beneficiarul aplicației se implică mai mult decât în celelalte faze. În mod asemănător, acesta trebuie să semneze raportul de test pentru a considera încheiată această fază de testare.
Capitolul 3 – Testarea sistemelor distribuite bazate pe tehnologia Internet
Componentele unui sistem distribuit
Aplicațiile distribuite constau în mai multe componente ce rulează pe mașini diferite, acestea
aplicații integrând acțiunile componentelor lor. Proiectarea aplicațiilor distribuite se axează nu
numai pe detaliile părților individuale, ci și pe realizarea unei integrări a componentelor
distribuite, astfel încât acestea să coopereze foarte bine între ele. Un sistem distribuit are ca
principale componente: hardware distribuit; și/sau control distribuit (soft de sistem); și/sau date
distribuite (soft de aplicații).
Hardware distribuit
1. Un sistem distribuit trebuie să conțină două sau mai multe sisteme de calcul, fiecare cu
procesorul și memoria lui locală. Acest aspect al distribuției fizice este foarte important în
definirea unui sistem distribuit.
2. Pentru ca aceste calculatoare distribuite să poată comunica, este nevoie de o formă de
rețea de comunicare.
3. Distribuirea calculatoarelor poate reflecta distribuirea fizică a aplicației sau
descompunerea funcțională a sistemului, unde sisteme de calcul diferite realizează funcții
diferite (de exemplu procesoarele dedicate).
Control distribuit
1. Sistemele conțin resurse fizice sub forma procesoarelor, imprimante, etc. precum și
resurse logice sub forma proceselor, fișierelor etc.
2. Strategia folosită pentru controlul resurselor poate fi centralizată ierarhic sau să permită o autonomie completă a procesoarelor individuale peste resursele locale. Această ultimă
abordare necesită o cuplare slabă între componentele sistemului (de exemplu rețelele de
calculatoare).
3. În multe cazuri se încearcă obținerea unei transparențe, în sensul că sistemul apare ca un
sistem unic, uniform, ascunzând distribuția fizică și neomogenitatea componentelor sale.
Datele distribuite
1. Una din resursele majore ce necesită control și din partea sistemului și din partea aplicației sunt datele.
2. Datele în curs de procesare pot fi distribuite prin: replicare (copii multiple la locații
diferite); partiționare (părți ale lor sunt stocate în diferite locații).
3. Datele sunt adesea distribuite atât pentru a crește toleranța la defecte, cât și pentru a
permite creșterea performanței prin stocarea datelor în apropierea zonelor unde sunt produse sau folosite.
Modele de organizare a aplicațiilor distribuite
Există următoarele modele de organizare a aplicațiilor distribuite:
1. aplicații tip „client ‐ server”, care presupun executarea unui volum important de prelucrări locale sau autonome și partajarea resurselor de calcul sau date
2. aplicații pe „cluster”, presupun utilizarea mai multor calculatoare conectate în rețea, sub
forma unei resurse unice
3. aplicații distribuite colaborative, care oferă posibilitatea participării mai multor persoane
la atingerea unui obiectiv sau a mai multora, prin intermediul tehnologiei calculatoarelor –
calcul plus comunicații
4. metacalculul, care se referă la utilizarea unui număr foarte mare de resurse de calcul,
foarte puternice și distribuite pe o arie mare, pentru rezolvarea unor probleme de o mare
complexitate.
Modele arhitecturale specifice. Modelul cu acces neuniform la memorie NUMA (Non‐Uniform
Memory Acces). NUMA cu memorii locale distribuite este o structură de sistem strâns cuplat
folosită de obicei în cazul supercalculatoarelor. NUMA ierarhic cu clustere (ciorchine sau
grupare de stații de lucru legate printr-o rețea care cooperează la realizarea unui țel comun).
Clusterul poate fi de tip NUMA sau UMA. Cazul conectării tip Butterfly local este cel mai rapid,
iar cel la distanță cel mai lent.
Figura 3.1. – Modelul NUMA
Modelele calcului distribuit
1. modelul “fermă de procesoare”: se caracterizează prin existența unui ansamblu de
elemente de prelucrare generice și de servere cu funcții specifice, ale căror facilități sunt
accesate de la stații de lucru, care în general au resurse de calcul și de memorare reduse.
2. modelul “client-server”: presupune executarea unui volum important de prelucrări locale
sau autonome și partajarea resurselor de calcul sau date.
3. modelul “data flow”: se bazează pe organizarea prelucrării conform unui graf în care nodurile sunt elemente de prelucrare, iar arcele sunt conexiuni logice prin care circulă mesajele.
4. modelul ierarhic: resursele de prelucrare sunt organizate (fizic sau logic) într-o rețea de
prelucrare arborescentă. În mod curent, nivelurilor mai înalte ale ierarhiei le sunt asociate
resurse de prelucrare mai puternice.
5. modelul “cache”: se bazează pe prelucrări realizate etapă cu etapă, efectuate de diverse
elemente de calcul, și pe combinarea rezultatelor parțiale pe un alt element de calcul, de
regulă mai puternic. O strategie de partajare a operațiunilor este adecvată în acest caz.
Modelul Client Server
În sistemele de operare pentru rețele de calculatoare se utilizează de cele mai multe ori
modelul client-server.În acest caz sistemul de operare conține, în afară de nucleu, un grup de procese numite servere, care oferă servicii proceselor utilizator, acestea devenind astfel clienți.
Există procese specializate care realizează diferite servicii, cum ar fi: lucrul cu fișiere,
compilare, tipărire etc. Un proces care are nevoie de o astfel de acțiune, o cere de la unul din
serverele care sunt dedicate pentru respectivul tip de problemă.În timpul execuției diferite procese pot fi atât client, cât și server; de exemplu serverul de fișiere poate deveni client pentru serverul care oferă timpul curent.
Dacă atât serverele, cât și clienții se execută în spațiul de memorie utilizator, structura
nucleului se simplifică mult, rolul acestuia din punctul de vedere al comunicației
restrângându-se la trimiterea și recepționarea de mesaje.Dacă realizarea comunicației se bazează pe operații de tipul transmisie sau recepție, înseamnă că elementele principale utilizate în programare sunt de tip operație de intrareieșire. Activitățile din timpul execuției unei aplicații distribuite sunt asociate de obicei, abstractizării de proces și ele nu vor putea să existe decât ca părți ale aplicației.
Un sistem client-server este realizat pe trei nivele, cel al prezentării, cel al aplicației și cel alaccesului la date. Separarea fizică a celor trei nivele se numește partiționarea aplicației.
Întotdeauna nivelul prezentării va fi implementat de către client. Împărțirea celorlalte două
nivele între client și server conduce la 5 stiluri diferite: prezentare distribuită; prezentare la
distanță; aplicație distribuită, când calculele sunt împărțite între client și server; date la
distanță; date distribuite.
Figura 3.1. – Arhitectura client/server
Aplicațiile distribuite acționează într-un mediu foarte diferit de cel al aplicațiilor client/server. în paradigma client/server, componentele aplicației software sunt folosite de către calculatorul client și calculatorul server. în mediul aplicațiilor distribuite, aplicația poate avea componente care să ruleze pe mai multe calculatoare din rețea. Diferența dintre client și server dispare. În mod evident, o componentă a unei aplicații distribuite acționează atât drept client, cât și ca server.
Avantajele sistemelor distribuite
1. Costuri reduse i s-a demonstrat economic că este mult mai ieftin să se folosească mai multe sisteme de calcul la rezolvarea unei probleme complexe, decât unul foarte performant.Acesta are un cost foarte mare și este dedicat, în general, numai un flux continuu de
probleme de calcul de foarte mari dimensiuni.
2. Modularitatea și simplitatea soft-ului – sistemele distribuite pot fi construite într-o manieră foarte modularizată, unde fiecare componentă permite interfațarea cu restul sistemului
(celelalte componente) sau servicii foarte bine definite. Modularitatea permite o proiectare
simplă a sistemului, instalare și întreținere mai simple.
3. Flexibilitatea și extensibilitatea – modularitatea sistemului permite schimbarea sau
modificarea elementelor de calcul fără a deranja major operațiile în curs de desfășurare. Prin
folosirea protocoalelor standard de comunicații este posibil să se includă într‐o rețea
echipamente provenind de la diferiți producători, rezultând o rețea omogenă.
4. Fiabilitate și integritate sistemele distribuite au proprietatea de a putea continua
operațiunile indiferent de starea unei părți a sistemului folosirea mai multor noduri de calcul
permite ca, în cazul defectării sau blocării unei resurse, sistemul să continue activitatea
resurselor critice, în acest caz, pot avea control dublu sau triplu dacă softul este proiectat în
stil tolerant la erori, sistemul poate continua absolut toate calculele în curs, prin redirectarea
task‐urilor de calcul care nu mai răspund spre alte procesoare
5. Performanța este în general definită în termenii timpului de răspuns la un anumit grad de
încărcare timpul de răspuns poate fi scăzut, în mod particular dacă majoritatea procesării
este făcuta local paralelismul datorat nodurilor multiple reduce defecțiunile și încetinirile ce
pot apărea la nivelul proceselor de calcul și generează o creștere a performanței globale
software-ul local poate fi folosit și la preprocesarea sau compactarea datelor, reducându-se
astfel încărcarea pe rețeaua de comunicație și crescând performanțele sistemului.
Rețelele de calculatoare au o extindere rapidă, intr-o multitudine de domenii cum ar fi sistemul bancar, administrația publică, alocarea temporara de resurse în hoteluri, rezervarea de bilete de avion rezervarea biletelor de tren etc. Aplicațiile moderne iau în considerare accesul unui număr cât mai mare de utilizatori, mai ales cand se prevede extinderea folosirii cardurilor și crește numărul acelora care utilizează Internetul.
Proiectarea aplicațiilor distribuite se axează nu numai pe detaliile părților individuale, ci și pe realizarea unei integrări a componentelor distribuite, astfel încât acestea să coopereze foarte bine între ele.
Principalele cerințe pentru aplicațiile distribuite sunt:
• interfețe puternice;
• fiabilitate foarte mare;
• securitate ridicată;
• viteză ridicată de prelucrare și transmitere a datelor.
În mod tradițional, aplicațiile software distribuite se bazează pe arhitectura client/server sau pe arhitectura multistrat (n-tier).
În contextul aplicațiilor client/server care utilizează baze de date, arhitectura client/server presupune existența unui server de baze de date(denumit server) și a unui modul software specific aplicației (denumit client) care prelucrează daÎtele și prezintă rezultatele, deci conține logica aplicației și logica prezentării. În acest sistem nu există noțiunea de obiecte, partea de client lucrează direct cu tabelele de date și procedurile stocate din baza de date.
În cadrul arhitecturii multistrat, un server de aplicații se interpune între aplicația de client și serverul de baza de date. Serverul de aplicații implementează logica de aplicație, iar clientul implementează logica de prezentare a sistemului. Avantajul major al arhitecturii multistrat față de arhitectura client/server îl reprezintă cresterea fiabilitătii.
Arhitectura Web confera acestora fiabilitate, scalabilitate și flexibilitate ridicată. Aceasta diferă față de arhitectura multistrat prin doua aspecte:
– aplicația client are o complexitate redusa, fiind un navigator Web;
– nivelul regulilor aplicației este bazat pe componete și nu este un singur sistem ce implementeaza intreaga construcție.
Figura 3.2. – Arhitectura Web
Componentele client sunt interfețele grafice utilizator și ruleaza în navigatoare Web precum Netscape Navigator sau Internet Explorer.Componentele Server care ruleaza într-un server de aplicații,furnizeaza logica procesului de afaceri.
Pentru testarea aplicațiilor distribuite bazate pe internet, trebuie luate în considerare urmatoarele aspecte:
-> capacitatea de utilizare; usurința în utilizare și intelegerea elementelor interfeței constituie elemente importante în acceptarea aplicației de catre clienti;
-> funcționalitatea; faptul ca aplicația realizeaza ceea ce isi propune prin specificații conduce la cresterea increderii utilizatorilor în aceasta și în firma producatoare;
-> compatibilitatea; avand în vedere faptul ca exista o multitudine de combinații intre sisteme de operare, navigatoare și aplicațiile care ruleaza în navigatoare, asigurarea compatibilitatii aplicației este o problema importanta, deoarece exista riscul ca o parte importanta dintre potentialii utilizatori să nu poate utiliza aplicația datorita incompatibilitatii și astfel sunt pierduti o serie de clienti;
-> performanta; timpul de raspuns și resursele ocupate reprezinta un aspect important pentru utilizatorii aplicației.
În cazul aplicațiilor Internet care acceseazǎ baze de date existǎ o multitudine de cauze care duc la funcționarea incorectǎ a acestora. De exemplu, testul eșuat al unei tranzacții într-o bazǎ de date poate avea mai multe cauze:
a. logica bazei de date: procedurile stocate, interogǎrile sau comenzile de actualizare, inserare sau ștergere contin erori;
b. logica serverului de aplicații: existǎ erori de proiectare sau de programare în cadrul funcțiilor implementate în serverul de aplicații;
c. logica procesǎrii tranzactiilor: ordinea eronatǎ a efectuǎrii unor operații conduce la eșuarea intregii tranzacții;
d. comunicația: în cazul unor probleme de comunicație la diverse niveluri, tranzacțiile fie nu au loc, fie se realizeazǎ incomplet sau incorect.
Testarea aplicațiilor bazate pe arhitectura Web, în plus fața de testarea aplicațiilor clasice, necesita o serie de teste specifice cum ar fi:
– testarea funcționala
– testarea de compatibilitate
– testarea continutului
– testarea performanței
– testarea de incarcare
– testarea securitații
– testarea serverului Web, al serverului de aplicații și testarea bazelor de date.
Testarea funcțională se realizează pentru a constata dacă site-ul se comportă conform cu specificațiile sale. Detaliile acestui tip de testare depind de natura site-ului Web si, în general, constă în verificarea legăturilor paginilor, testarea formularelor, verificarea tranzacțiilor pentru comertul electronic și pentru baze de date, testarea apleturilor java.
Prin testarea de compatibilitate se urmăreste aspectul și comportamentul site-ului Web în raport cu o varietate de sisteme de operare și de navigatoare Internet. Această testare scoate în evidentă problemele cu controalele ActiveX, apleturile Java, funcțiile JavaScript sau VBScript și formulare din pagini. La ora actuală există peste 100 de combinații posibile intre diverse sisteme de operare Windows și diverse versiuni ale navigatoarelor NetScape și Internet Explorer.
Pentru testarea conținutului se urmăreste corectitudinea și asezarea în pagina a textelor, imaginilor și a fisierelor de animatie și video din cadrul site-ului.
Prin testarea performanțelor se măsoară comportamentul site-ului Web în diverse condiții de trafic.
Testarea de incărcare se utilizează pentru a verifica daca site-ul Web poate gestiona un anumit număr de utilizatori care il accesează concurent, în limite acceptabile ca timp de răspuns.
Testarea securitatii tranzactiilor efectuate este foarte importanta pentru aplicațiile de comert electronica avand în vedere faptul ca sunt vehiculate date confidențiale, la care daca au acces persoane neautorizate sau rauvoitoare se pot produce pierderi materiale importante.
Testarea serverului Web are în vedere testarea interacțiunilor dintre serverul Web și serverul de aplicații, verificarea integritatii bazei de date în cadrul serverului de baze de date, verificarea faptului ca scripturile ASP, PHP sau JSP se execută correct pe server.
Testarea serverului de aplicații se realizează tinăndu-se seama de caracteristicile funcționale și structurale ale acestuia. Se testează componentele serverului, folosind metode clasice de testare, precum și metode de testare care iau în considerare tranzacțiile și comunicațiile asincrone dintre aceste componente.
Testarea bazelor de date presupune verificarea executarii corecte a interogarilor și operatiilor de adaugare și actualizare a datelor, precum și verificarea conexiunilor dintre site-ul Web și baza de date.
Testarea aplicațiilor distribuite bazate pe arhitectura Web este realizata fie de catre echipe de specialitate din cadrul departamentului de asigurare a calitatii a firmei, fie de catre o firma specializata în testare(out-sourcing).
Capitolul 4 – Testarea automată
În noua economie, producătorii de soluții IT sunt confruntați cu o nouă cerință care îi obligă să schimbe total modul de constructie a unui produs, fără a face compromisuri de calitate. A fi primul pe piață cu ultimele tehnologii este mai important ca oricând. Lucrând cu o infrastructura software și hardware din ce în ce mai complexă, confruntați cu creșterea continuă a cerințelor de calitate și cunecesitatea reducerii costurilor, firmele de software încep să prețuiască tot mai mult soluții solide, inginerești, de dezvoltare de software. Testarea produsului este în software o componentă majoră în procesul de dezvoltare. În limbaj de specialitate se discută despre asigurarea calității (Quality Assurance).
Firmele din industria tradițională – de ex. industria de mașini, de construcții, de produse electronice sau alimentare au de zeci de ani departamente de testare și verificare a calității. În materie de software, organizarea și automatizarea muncii de testare și verificare a produselor a început din motive istorice evidente abia în anii '80. Testarea manuală, mult timp văzută ca singura soluție de a descoperi eventualele defecte, întârzie foarte mult lansarea pe piață a produsului și induce cheltuieli semnificative mai ales în cazul descoperirii efectelor laterale – atât în procesul dezvoltării unei aplicații cât și în cazul de schimbări ulterioare.
Totodată procedurile de testare manuală, prin natura lor limitată, nu reușesc să descopere toate defectele și nu au nicio șansă să simuleze condiții de utilizare simultană, intensivă, a unei aplicații.
Există numeroase căi de a îmbunătăți procesul de testare, una dintre cele mai eficiente fiind testarea automată. Testele automate execută o secvență de acțiuni fără intervenție umană și pot simula utilizarea unei aplicații în condiții de simultaneitate ridicată. În general, majoritatea produselor necesită să fie testate de mai multe ori, pe mai multe platforme software și hardware, ca și după schimbările ulterioare sau la lansarea unei noi versiuni de produs. Prin folosirea testării automate, costurile testărilor repetate se reduca proape la zero.
Cele mai importante beneficii sunt:
• acoperirea tuturor etapelor de testare de la concepție până la lansare
• posibilitatea simulării testării cu mai mulți utilizatori
• posibilitatea repetării testelor
• creșterea siguranței în produs.
Un sistem de testare automată trebuie să aibă la bază două caracteristici principale:
• module reutilizabile
• întreținerea și urmărirea activității dintr-un singur punct de control
De aceea una din calitățile care trebuie să le aibă un astfel de sistem este capabilitatea de a fi ușor configurat și adaptat în același ritm cu software-ul ce se testează. Sistemele de testare automată sunt o tehnologie în plină dezvoltare care au ca scop descoperirea și raportarea eventualelor defecte, mărirea longevității produsului și reducerea procesului de întreținere. Testarea automată înseamnă mai mult decât o simplă captură de ecran și răspunsul la câteva scripturi: ea trebuie să înceapă cu planificarea și design-ul procedurii de testare, să conțină o serie de teste repetabile, o interfață de management al scenariilor de test și un mecanism de raportare și gestionare a bug-urilor descoperite în urma testării. Un sistem de test evoluat sprijină utilizatorii printr-un sistem de documentare pe tot parcursul acestui proces.
De ce este testarea automată atât de importantă pentru companii?
Testarea automată salvează timp și bani – testele software trebuie să fie repetate des în timpul ciclului de dezvoltare pentru a asigura calitatea. De fiecare dată cand codul sursa este modificat testele trebuie repetate. Pentru fiecare release al software-ului tb testate toate sistemele de operare și configuratiile hardware pe care aplicația le suportă. Dacă se efectuează manual aceste teste, duce la costuri mari și timp consumat. Odata create testele automate pot fi rulate și rerulate fără cost aditional și sunt mult mai rapide ca testele manuale. Automatizarea testelor pot reduce timpul testelor repetitive de la cateva zile la cateva ore. Automatizarea economiseste timp, timp ce se poate traduce în economisirea costurilor.
Testarea imbunătăteste acuratetea – chiar și cei mai constiinciosi testeri vor face greseli în timpul testarii manuale care poate deveni foarte monotona cand e repetitivă. Testele automate execută aceeasi pasi, precis, de fiecare dată cand sunt executate și nu omit să inregistreze detaliile rezultatelor.
Cresterea acoperirii testelor – testarea automată poate creste profunzimea și aria de testare ce ajută la cresterea calitătii produsului. Testele lungi care sunt adesea evitate de testeri pot fi acum rulate fara să fie supravegheate. Ele pot fi rulate chiar în paralel pe mai multe calculatoare cu configuratii diferite. Testele automate se pot uita în interiorul uneia aplicații și pot vedea continutul memoriei, tabele cu date, continutul fisierelor și starea programelor pentru a determina daca produsul se comporta conform asteptarilor. Testele automate pot executa usor sute de test case-uri diferite și complexe la fiecare rulare reusind să asigue o acoperire ce este impsobil de facut prin testarea manuala. Testerii sunt eliberati de testarea manuala repetitiva avdn mai mult timp pentru crearea de noi teste automate și mult mai complexe.
Automatizarea face ceea ce testarea manuala nu poate face – pana și cele mai mari departamente de dezvoltare software nu pot simula controlat testarea aplicației cu cateva sute de useri. Testele automate pot simula zeci, sute și chiar mii de useri virtuali care interactioneaza cu reteaua și cu aplicația
Testarea automatizata ajuta și developerii și testerii – testele automate share-uite pot fi folosite și de programatori pentru a identifica probeleme repede inainte de a la trimite la QA. Teestele pot rula automat atunci cand codul este modificat și pot notifica echipa daca acestea pica. Facilitatile ca acestea economisesc timp pentru progamatori și creste increderea.
Creste moralul echipei – acest lucru este greu de masurat dar a fost exeperimentat și testele automatizate pot creste moralul echipei. Automatizand task-urile repetitive cu ajutorul testelor, acorda mai mult timp aomenilor din echipa pentru proiecte sau task-uri mult mai interesante și challenging. Oamenii isi imbunatatesc
Testarea Manuala vs Testarea Automată
Nu toate testele pot fi automatizate și de cele mai multe ori poate fi dificil de decis ce să se automatizeze și ce să se testeze manual. în urmatoarele randuri va prezentam cateva avantaje și dezavantaje ale ambelor solutii.
Introducere in WebDriver
WebDriver este un framework rapid si curat pentru testarea automata a aplicatiilor web. De ce este nevoie de acest framework? Cum poate sa ajute in rezolvarea problemelor, mai mult decat framework-urile deja existente?
De exemplu, Selenium, este bine definit si un foarte popular framework; este un tool care pune la dispozitie o interfata care functioneaza pe un numar mai mare de browsere si care permite scrierea testelor in aproape orice limbaj imaginabil, de la Java sau C# la PHP sau Erlang!. Este unul din primele proiecte Open Source care aduc testarea bazata pe browsere si, deoarece este scrisa in JavaScript face posibila adaugarea de noi browsere care ar putea fi lansate.
Ca orice mare proiect, nu este perfect. Selenium este scris in JavaScript, iar acest lucru aduce un minus signifiant: browserele impun un model de securitate foarte stricta pe orice JavaScript pe care il executa pentru a putea proteja utilizatorul de la scriptarea malitioasa. Exemple in care acest model de securitate face testarea mai grea ar fi cand se incearca uploadarea unui fisier (IE nu permite JavaScript sa schimbe valoarea unui element dintr-un fisier INPUT) si cand se incearca navigarea intre domenii (din cauza problemei politicii originii semnalului de baza).
Aditional, este un produs matur, API pentru Selenium RC a crescut in timp si acest lucru a facut sa fie din ce in ce mai greu de inteles cum ar trebui sa fie cat mai bine utilizat. De exemplu, nu este din prima evident daca ar trebui sa fie folosit „ type” sau „ typeKeys” pentru a introduce un text intr-un formular de control. Desi tine de estetica, uni utilizatori gasesc acest produs intimidant si greu de folosit.
Terminology
Selenium Core sau simplu Core este un set de script-uri JavaScript care controleaza browser-ul, imitand activitatea unui utilizator. Aceste script- uri sunt introduse in pagina web in functie de lista actiunilor scrise intr-un tabel special de comanda din HTML sau Selense, astfel simuland activitatea utilizatorului.
Selenium RC sau Selenium Remote Control sau Selenium 1 primeste comenzi Selenium Core prin HTTP si le executa pe o unitate remote, folosind proxy- uri pentru a preveni restrictia aceleasi origini. Acest lucru permite scrierea testelor in alte limbaje ca C#, Python, Perl, PHP, Java and Ruby (prin legaturi de limbaje pentru Selenium Core).
Selenium- WebDriver sau WebDriver sau Selenium 2 este un succesor al Selenium RC. Face acelasi lucru, dar intr-un mod diferit: in loc sa introduca un cod JavaScript in browser pentru a simula activitatea unui user, foloseste chiar suportul browser-ului pentru automatizare ( fiind diferit pentru fiecare browser). De asemenea, in loc sa foloseasca un dictionar API ( folosit in Selenium RC), ofera posibilitatea mai convenabila a orientarii in fuctie de obiect API.
Selenium Server permite utilizarea Selenium- WebDrive pe o unitate remote.
Selenium IDE este un add Firefox care inregistreaza activitatea utilizatorului si creaza teste bazata pe aceasta activitate. De asemena poate rula testele invers si le poate salva in programe de limbaje diferite.
Selenium- Grid permite rularea testelor pe unitati diferite impotriva unor browsere in paralel; cu alte cuvinte permite executarea testelor distribuite.
Selense este un „ limbaj” special reprezentat de un set de comenzi Selenium care ruleaza testele. O astfel de secventa de comanda se numeste test script.
De unde sa incepem? (mai bine zici Avantaje)
Este bine sa se inceapa cu Selenium IDE. Te ajuta sa devi mai familiar cu comenzile din Selenium si se va putea vedea cum functioneaza Selenium prin rularea scripturilor test direct din tool. Nota, cand se ruleaza testele prin Selenium IDE, se executa intr-un mod diferite decat atunci cand sunt rulate folosind alte tool- uri Selenium. Daca este nevoie sa se testeze aplicatii, mai bine se utilizeaza Selenium WebDriver sau Selenium RC. Totusi, pe primul loc ar fi Selenium WebDriver, pentru ca este varianta imbunatatita a Selenium RC, care, oficial a fost depreciat.
Putina Istorie
2004- Jason Huggins a creat tool-ul bazat pe JavaScript pentru testarea automatizata numit Selenium ( stiut ca si Selenium Core). Mai tarziuSelenium Remote Control sau Selenium RC a fost dezvoltat sa fie adresat politicii de browser cu aceleasi origini si permite multor conexiuni de limbaje sa controloze un browser de la distanta.
2006- Simon Stewart a inceput sa lucreze la un alt tool de testare web denumit WebDriver.
2009- Selenium RC si WebDriver fuzioneaza intr-un singur proiect denumit Selenium WebDriver sau Selenium 2.0.
2013- Este lansat primul draft functional al WebDriver, API W3C.
Selenium WebDriver
Introducere in WebDriver
Trasatura principala a Selenium 2.0 este integrarea de WebDriver API. WebDriver este proiectat pentru a pune la dispozitie o interfata de programare mai simpla si mai concisa adresandu-se unor limite a Selenium- RC API. Selenium- WebDriver a fost proiectat pentru a sustine mai bine pagini de web dinamice unde elementele paginilor se pot schimba fara ca aceastea sa fie reincarcate. Scopul WebDriver este acela de a pune la dispozitie well- design object oriented API (nu stiu cum sa iti traduc aici, decat dupa cuvinte) care ofera un suport imbunatatit pentru aplicatiile avansate si moderne de testare.
Cum se compara WebDriver „ Driver”, Browser-ul, cu Selenium- RC?
Selenium- WebDriver face apel direct la browser folosind suportul nativ al acestuia pentru automatizare. Cum se face acest apel direct si trasaturile pe care le suporta depind de browser-ul folosit.
Selenium- RC lucreaza la fel cu fiecare browser. „ Injecteaza” functii JavaScript in browser cand acel browser este incarcat si atunci foloseste functiile JavaScript pentru a conduce AUT din browser.
Introducing the Selenium-WebDriver API by Example
Selenium-WebDriver API by Example
WebDriver este un tool pentru automatizarea aplicatiilor de testare si in special verifica ca acestea sa functioneze conform asteptarilor. Tinteste sa ofere un API prietenos care este usor de explorat si de inteles, mai usor de folosit decat Selenium- RC ( 1.0) API, care sa faca testele mai usor de citit si mentinut. Nu este legat de nici un framework in special, astfel poate fi folosit la fel de bine si in unit testing sau prin vechea metoda „ principala”.
package org.openqa.selenium.example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Selenium2Example {
public static void main(String[] args) {
// Create a new instance of the Firefox driver
// Notice that the remainder of the code relies on the interface,
// not the implementation.
WebDriver driver = new FirefoxDriver();
// And now use this to visit Google
driver.get("http://www.google.com");
// Alternatively the same thing can be done like this
// driver.navigate().to("http://www.google.com");
// Find the text input element by its name
WebElement element = driver.findElement(By.name("q"));
// Enter something to search for
element.sendKeys("Cheese!");
// Now submit the form. WebDriver will find the form for us from the element
element.submit();
// Check the title of the page
System.out.println("Page title is: " + driver.getTitle());
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return d.getTitle().toLowerCase().startsWith("cheese!");
}
});
// Should see: "cheese! – Google Search"
System.out.println("Page title is: " + driver.getTitle());
//Close the browser
driver.quit();
}
}
Exemplul de mai sus este un exemplu bun pentru a intelege principiul de functionare al acetui tool de automatizare dar din experienta proprie, folosind Selenium in acest mod se poate ajunge la scripturi foarte mari, greu de citit si nescalabile la care mentenanta se poate face foarte greu ajungand sa ocupe foarte mult timp, deci costuri mai mari.
In acest sens pentru ca aceasta problema de scalabilitate sa fie evitata si pentru a face folosirea tool-ului mult mai usoara si inteligibila s-a creat un pattern de folosire numit Page Objects:
Ce reprezinta Page Objects:
Cand se scriu teste pentru o pagina web, trebuie sa se faca referire la elementele din acea pagina web pentru a putea accesa link-urile si a determina ce se va deschide. Cu toate acestea, daca se scriu teste care manipuleaza elemntele HTML direct, testele vor fi mai fragile la schimbarile din UI. Un obiect din pagina impacheteaza o pagina HTML sau un gragment cu o aplicatie specifica API, permitand manipularea elementelor din acea pagina fara sa fie nevoie sa se caute pe langa in HTML.
The basic rule of thumb for a page object is that it should allow a software client to do anything and see anything that a human can. It should also provide an interface that's easy to program to and hides the underlying widgetry in the window. So to access a text field you should have accessor methods that take and return a string, check boxes should use booleans, and buttons should be represented by action oriented method names. The page object should encapsulate the mechanics required to find and manipulate the data in the gui control itself. A good rule of thumb is to imagine changing the concrete control – in which case the page object interface shouldn't change.
Regula de baza a degetului mare pentru un obiect pagina este aceea ca ar trebui sa permita unui soft client sa faca si sa vada tot ce poate si un om. De asemenea ar trebui sa ofere o interfata care este usor de programat si care ascunde widgetry- urile care stau la baza in fereastra. Deci, ca sa accesezi un camp de text ar trebui sa existe metode accesor care preia si returneaza un string, verifica incaperile care folosesc booleans si butoanele care ar trebui reprezentate prin metode orientate denumite. Obiectul din pagina ar trebui sa encapsuleze mecanica necesara pentru a gasi si a manipula datele din gui singur. O buna regula a degetului este de a imagina schimbarea concreta a controlului- in acest caz interfata obiectului pagina nu ar trebui sa se schimbe.
In ciuda termenului de obiect „ pagina”, aceste obiecte nu ar trebui, de obicei, sa fie construite pentru fiecare pagina, dar mai bine doar pentru elementele signifiante de pe o pagina. Deci o pagina care arata multiple albume ar trebu sa aibe un obiect pagina lista de albume care sa contina mai multe obiecte pagina album. Acolo ar fi si un header obiect pagina si un footer obiect pagina., Acestea fiind spuse, o parte din ierarhia unui UI complex este acolo doar ca si structura UI- astfel de structuri nu ar trebui aratate de catre pagina obiect. Regula degetului este un model de structura in pagina care face sens la utilizator din aplicatie.
Similar si daca se navigheaza catre o alta pagina, obiectul pagina initial ar trebui sa returneze un alt obiect pagina pentru noua pagina. In general operatiunile pagina obiect ar trebui sa returneze tipuri fundamentale ( strings, date) sau alte pagina obiect.
Sunt diferente de opinii referitoare la pagina obiect. Daca sa includa assertions si ele sau doar sa ofere date pentru scripturile testelor pana la assertions. Sustinatorii introducerii assertions in pagina obiect spun ca acest lucru ajuta la evitarea duplicarii de assertions in scripturile testelor, face mai usor de oferit si mai bine mesajele de eroare si suporta mai mult TellDontAsk style API. Sustinatorii de assertion- free pagina obiect spun ca introducand assertions amesteca responsabilitatile in oferirea accesului la informatiile din pagina dupa logica assertion si conduce catre o pagina obiect umflata.
De preferat sa nu fie assertions in pagina obiect. Se poate evita duplicarea prin punerea la dizpozitie a unei librarii assertion pentru assertions comune- care, de asemenea, duce la o diagnosticare buna.
Obiectele pagina sunt de obicei folosite pentru testare, dar nu ar trebui sa creeze assertions singure. Responsabiliatea lor este de a oferi acces la starea din partea din spate a paginii. Depinde de clientii testori sa produca logica assertion.
Acest tipar a fost descris acest tipar in ceea ce priveste HTML-ul, dar acelasi tipar se poate aplica la fel de bine oricarei tehnologii UI. Acest tipar a fost folosit cu succes pentru a ascunde detaliile unui swing UI Java si bineinteles este folosit cu orice framework UI existent.
Problemele de concurenta sunt un alt topic pe care o pagina obiect le poate incapsula. Acest lucru ar putea implica ascunderea asincronizarea din operatiunile asincron care nu apar utilizatorului ca si asincron. De asemenea ar putea implica incapsularea impartirii problemelor in framework-ul UI unde trebuie sa ne ingrijoreze alocarea unui comportament intre UI si impartirea lucratorilor.
Paginile obiect sunt de obicei folosite in testare, dar de asemenea pot fo folosite pentru a oferi o interfata scriptata deasupra unei aplicatii. De obicei e mai bine sa pui o interfata scriptata sub UI, care este de obicei mai putin complicata si mai rapida. Totusi cu o aplicatie care pune prea mult comportament in UI apoi folosind pagini obiect se face cea mai buna treaba rea.
Modelele care tintesc sa mute logica din UI fac sa fie mai putin folositor de testat prin UI si astfel reduce nevoia de pagini obiect.
Paginile obiect sunt un exemplu clasic de incapsulare- ascund detaliile unei structuri UI si a widgetry- urilor de alte componente ( testele). Este un bun principiu de design care sa se uite dupa astfel de situatii in timp ce se dezvolta ( developeaza, nu stiu cum sa zic)- cum se pot ascunde unele detalii de restul software- ului? Ca orice incapsularea aceasta duce la doua randamente benefice. Limitarea logicii care manipuleaza UI la un singur loc poate fi modificata fara a fi afectate alte componente din sistem. Un beneficiu consecinta este acela ca face clientul (testul) cod mai usor de inteles pentru ca logica de acolo este intentia testului nu aglomerarea cu detaliile UI.
In continuare folosind Selenium WebDriver si Page Objects am scris in Java cate teste pentru clientul de email Gmail.
Am scris o suita de teste pentru interfata de login a acestui client de email, teste care vor acoperi cele mai multe cazuri posibile ce se pot intampla, inclusiv verificarea textelor din aceasta pagina.
Pentru a crea interfata paginii vom implementa o clasa LoginPage.class in care vom adauga toate elementele paginii si deasemene metodele aferente actiunilor ce se pot face pe aceste elemente:
public class LoginPage {
public WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
}
//fields and buttons
By usernameInput = By.id("Email");
By passInput = By.id("Passwd");
By loginButton = By.id("signIn");
By staySigned = By.id("PersistentCookie");
By needHelp = By.id("link-forgot-passwd");
By newAccount = By.id("link-signup");
//texts and images in page
By h1 = By.xpath("html/body/div[1]/div[2]/div[1]/h1");
By h2 = By.xpath("html/body/div[1]/div[2]/div[1]/h2");
By profileImg = By.id("profile-img");
By profileName = By.id("profile-name");
By profileEmail = By.id("reauthEmail");
//error messages
By userOrPassIncorrectError = By.id("errormsg_0_Passwd");
By noUserError = By.id("errormsg_0_Email");
public LoginPage UsernameInputFill(String user) {
driver.findElement(usernameInput).sendKeys(user);
return this;
}
public LoginPage PassInputFill(String pass) {
driver.findElement(passInput).sendKeys(pass);
return this;
}
public LoginPage CheckStaySigned() {
driver.findElement(staySigned).click();
return this;
}
public String H1Value() {
return driver.findElement(h1).getText();
}
public String H2Value() {
return driver.findElement(h2).getText();
}
public String UserOrPassIncorrectError() {
return driver.findElement(userOrPassIncorrectError).getText();
}
public String NoUserError() {
return driver.findElement(noUserError).getText();
}
public Integer ProfileImgExist() {
return driver.findElements(profileImg).size();
}
public String ProfileName() {
return driver.findElement(profileName).getText();
}
public String ProfileEmail() {
return driver.findElement(profileEmail).getText();
}
public LoginPage ClickInput() {
driver.findElement(passInput).click();
return this;
}
public NeedHelpPage ClickNeedHelp() {
driver.findElement(needHelp).click();
return new NeedHelpPage(driver);
}
public NewAccountPage ClickNewAccount() {
driver.findElement(newAccount).click();
return new NewAccountPage();
}
public AccountMainPage LoginClickOk() {
driver.findElement(loginButton).click();
return new AccountMainPage(driver);
}
public LoginPage LoginClickNok() {
driver.findElement(loginButton).click();
return this;
}
public AccountMainPage LoginOk() {
UsernameInputFill(Helper.USER);
PassInputFill(Helper.PASSWORD);
return LoginClickOk();
}
}
Luand in considerare clasa creata anterior avem urmatoarele Test Case-uri ce s-au automatizat pentru pagina de login. Voi scrie detaliat fiecare test case in ce consta si sub el codul scris pentru automatizare.
TC1: Login OK
Pasi:
Mergi la pagina de login: http://gmail.com
Introdu user valid
Introdu parola valida
Click Sign In
Rezultat asteptat: Trebuie sa ajungem in pagina ce reprezinta contul user-ului
@Test
public void LoginOk() {
LoginPage loginpage = new LoginPage(driver);
CommonMethods commonmethods = new CommonMethods(driver);
loginpage.UsernameInputFill(Helper.USER);
loginpage.PassInputFill(Helper.PASSWORD);
AccountMainPage accountMainpage = loginpage.LoginClickOk();
commonmethods.WaitUntilPresent(accountMainpage.composeButton, 20);
}
TC2: Login fara user
Mergi la pagina de login: http://gmail.com
Introdu parola
Click Sign In
Rezultat asteptat: tb sa apara mesajul de eroare „Enter your email address”
@Test
public void LoginWithoutUser() {
LoginPage loginPage = new LoginPage(driver);
loginPage.UsernameInputFill("");
loginPage.PassInputFill(Helper.PASSWORD);
loginPage.LoginClickNok();
Assert.assertEquals(loginPage.NoUserError(),"Enter your email address.");
}
TC3: Login fara parola
Mergi la pagina de login: http://gmail.com
Introdu user
Click Sign In
Rezultat asteptat: tb sa apara mesajul de eroare „Enter your password.”
@Test
public void LoginWithoutPassword() {
LoginPage loginPage = new LoginPage(driver);
loginPage.UsernameInputFill(Helper.USER);
loginPage.PassInputFill("");
loginPage.LoginClickNok();
Assert.assertEquals(loginPage.UserOrPassIncorrectError(),"Enter your password.");
}
TC4: Login utilizator gresit
Mergi la pagina de login: http://gmail.com
Introdu user invalid
Click Sign In
Rezultat asteptat: tb sa apara mesajul de eroare „The email or password you entered is incorrect.” si deasemenea cerculetul rosu cu semnul intrebarii cu link catre Help Page
@Test
public void LoginWithWrongUser() {
LoginPage loginPage = new LoginPage(driver);
loginPage.UsernameInputFill("sdsadad");
loginPage.PassInputFill(Helper.PASSWORD);
loginPage.LoginClickNok();
Assert.assertEquals(loginPage.UserOrPassIncorrectError(),"The email or password you entered is incorrect. ?");
loginPage.RedCircleExists();
}
TC5: Login parola gresita
Mergi la pagina de login: http://gmail.com
Introdu user invalid
Click Sign In
Rezultat asteptat: tb sa apara mesajul de eroare „The email or password you entered is incorrect.” si deasemenea cerculetul rosu cu semnul intrebarii cu link catre Help Page
@Test
public void LoginWithWrongPassword() {
LoginPage loginPage = new LoginPage(driver);
loginPage.UsernameInputFill(Helper.USER);
loginPage.PassInputFill("asdasd");
loginPage.LoginClickNok();
Assert.assertEquals(loginPage.UserOrPassIncorrectError(),"The email or password you entered is incorrect. ?");
loginPage.RedCircleExists();
}
TC6: Campul parola sa fie de tip password(transforma caracterele introduse in stelute la introducerea lor)
@Test
public void VerifyPassInputType() {
LoginPage loginpage = new LoginPage(driver);
Assert.assertEquals(loginpage.GetPasswordTypeAttribute(), "password");
}
TC7: Toate textele din pagina: One Google Account for everything Google, One account. All of Google si Sign in to continue to Gmail sa existe
public void ValidateTextsInPage() {
LoginPage loginPage = new LoginPage(driver);
Assert.assertEquals(loginPage.H1Value(), "One account. All of Google.");
Assert.assertEquals(loginPage.H2Value(), "Sign in to continue to Gmail");
}
TC8: Click pe link-ul Need help sa duca pe pagina cu titlul: Google Account Recovery
@Test
public void ClickOnNeedHelp() {
LoginPage loginpage = new LoginPage(driver);
loginpage.ClickNeedHelp();
Assert.assertEquals(driver.getTitle(), "Google Account Recovery");
}
TC9: Click pe Create an account sa duca pe pagina in care se poate crea un cont nou si in care exista titlul: Google Accounts<de vazut>
@Test
public void ClickOnNewAccount() {
LoginPage loginpage = new LoginPage(driver);
loginpage.ClickInput();
loginpage.ClickNewAccount();
Assert.assertEquals(driver.getTitle(), "Google Accounts");
}
Folosind acelasi principiu s-au creat si 2 scenarii de test mai complexe care acopera mai multe pagini conexe cu pagina de login pentru a arata si modul cum se poate naviga dintr-o pagina in alta si deaemenea cum se pot folosi elemente din fiecare pagina folosind clasele si metodele fiecarei pagini:
S1:<scenariu1>
S2:<scenariu2>
BIBLIOGRAFIE:
Computer Networks – ANDREW TANENBAUM
http://www.freetutes.com/systemanalysis/sa9-testing-quality-assurance.html
Glenford Myers, Corey Sandler, Tom Badgett-Art of Sotware Testing
http://en.wikipedia.org/wiki/Software_testing
http://www.softwareqatest.com/
BIBLIOGRAFIE:
Computer Networks – ANDREW TANENBAUM
http://www.freetutes.com/systemanalysis/sa9-testing-quality-assurance.html
Glenford Myers, Corey Sandler, Tom Badgett-Art of Sotware Testing
http://en.wikipedia.org/wiki/Software_testing
http://www.softwareqatest.com/
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Testarea Sistemelor Distribuite Bazate pe Tehnologia Internet (ID: 124552)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
