Framework DE Automatizare CU Selenium Webdriver

FRAMEWORK DE AUTOMATIZARE CU SELENIUM WEBDRIVER

Cu prins

I. STADIUL ACTUAL

II. FUNDAMENTAREA TEORETICĂ

2.1.Generalitati testare

2.2 Selenium Generalități

2.3 Selenium RC sau Remote Control și IDE

2.4 Selenium Webdriver compatibilități

2.5 WebDriver și Selenium-Server

2.6 Webdriver localizarea elementelor

2.7 Seleium WebDriver DRIVERS

2.8 Selenium Waits (timpi de așteptare)

2.8.1 Explicit wait

2.8.2 Implicit wait

2.9 De ce să automatizăm?

2.10 BlackBox automation

2.11 Greșeli comune în crearea framework-ului de testare automată

2.12 Abordarea creării unui automation framework

2.13 Straturile unui framework

2.14 Reguli ce ajută la creearea unui framework

2.15 Domain Specific Languages

2.16 Tipuri de DSL

2.17 Rularea testelor

2.18 Drivere de test

2.19 Greșeli comune în designul testelor

2.20 Automatizarea lucrurilor grele

2.21 Errori VS Eșecuri

2.22 Integrare continuă

2.23 Scalarea

2.24 Lucrul în metodologia Agile

2.25 Testarea pe diferite versiuni de browsere

III IMPLEMENTAREA SOLUȚIEI ADOPTATE ȘI REZULTATE EXPERIMENTALE

3.1 Generalități implementare

3.2 Interfața Framework-ului

3.3 Proiectul Framework

3.4 Proiectul Services

3.5 Proiectul TestCases

3.6 Registration test case

3.7 Trecere prin debug pentu principalele flow-uri din teste

3.7.1 Debug deschidere Chrome driver

3.7.2 Debug pentru click pe element

3.7.3 Debug pentru raportare( logging)

IV. CONCLUZII

4.1 Beneficii aduse de automatizare

4.2 Îmbunătățiri ce pot fi aduse

V. BIBLIOGRAFIE

VI. ANEXE

Anexa1- Exemplu de Testcase

I. STADIUL ACTUAL

Testarea se poate împarți în două ramuri cea a testării manuale în care nu se folosește nici un script sau tool de automatizare, în care testerul ia rolul unui user al aplicației pentru a găsi comportamentele neasteptare sau defectele aplicației.Bineînțeles testarea manuală este și ea împărțită în mai multe stagii cum ar fi unit testing; integration testing ;system testing sau acceptance testing . Se folosesc planuri de test , cazuri de test, scenarii de test pentru a putea evalua cât mai bine aplicația și problemele sale.Pe lângă tipurile acestea de testare manuală mai există și exploratori testing în care testerii explorează aplicația pentru a găsi defacte.

În momentul de față se încearcă trecerea de la testarea manuală în proporții cât mai mari spre testarea automată.Deși nu tot timpul testarea automată este o soluție sau nu e o soluție viabilă din punct de vedere al timpului sau al mentenanței codului de automation testarea automată este o armă foarte puternică în special pentru testele de regresie.Automatizarea constă în scrierea de către testeri a unor scripturi care folosesc alte programe software pentru a testa softwareul aflat sub test.Testare automată este folosită pentru a rerula în mod rapid și repetat teste ce s-au executat manual.Pe lângă regression automationul este folosit la peformance testing, stress testing etc.

Procesul de automatizare ar trebui să aibă loc în cazul în care avem de-a face cu proiecte foarte mari, proiecte care necesită testarea în aceeași zonă în mod repetat, în cazul în care cerințele (requirements ) nu se schimbă foarte des, este necesata o testare a performanței cu mulți useri virtuali și un alt factor important dacă timpul permite așa ceva.

Pentru a putea automatiza cu succes trebuie să luăm în calcul câteva elemente cum ar fi identificarea zonelor unde testarea trebuie făcută, selecția unui tool de automation care să facă față nevoilor, modul de executare al scripturilor, creearea de raporturi de test. În momentul de față există o mare varietate de tool-uri de testare automată cum ar fi : TestComplete, LoadRunner, HP Quick Test Professional, Ranorex, Xamarin test cloud etc. însă în ciudă varietăți mari de software disponibil particularitățile multor aplicații fac că nici unul din tool-urile existențe pe piață să se preteze tuturor nevoilor.

Unul din cele mai fericite cazuri este acela în care pe lângă scripturile pe care vrei să le rulezi îți creezi și propriul framework de automation .Unul dintre principalele impedimente în realizarea framework-ului este timpul și tot odată numărul de indivizi necesari pentru a fi implicați în realizarea acestuia cât și complexitatea construirii.

Unul din cele mai versatile tool-uri în domeniul automatizării este Selenium Web Driver.Programul pune la dispoziție un set de clase prin intermediul cărora se pot accesă diferite elemente de UI .Ceea ce este foarte utilă este versatilitatea Selenium-ului care este compatibilă cu o gamă largă de limbaje cum ar fi: C#, Pe Pearl, Ruby, php, Python, Java. Odată adăugate referințele librăriilor Selenium în cazul C# în Visual Studio se poate trece la exploatarea programului.

II. FUNDAMENTAREA TEORETICĂ

2.1.Generalitati testare

Principalele tipuri de testare și testele aferente lor sunt:

Non-Functional:

Compatibility

Load test

Stress test

Recovery Security

Hardware resource

Usability

Protability

Static testing:

Requirements

Specifications

Code review

Functional:

Smoke testing

Unit testing

Sanity test

Whitebox

Blackbox

Graybox

Positive testing

Negative testing

Regression

Integration

Feature test

System testing

End to end testing

Exploratory testing

Back to back testing

Fig. 2.1 Ciclul Testarii

Ciclul de viață al testării începe odată cu cerințele create de beneficiarul proiectului. Ulterior are loc crearea unui plan de test , designul pentru teste , cod. Urmează executarea și raportarea rezultatelor testării însoțite de un raport cu defectele existente. Dacă este cazul patching și bineînțeles lansarea produsului.

Gelperin și Hetzel au analizat evoluția conceptului de testare a unui sistem informatic și au împărțit evoluția acestuia în mai multe etape, în funcție de filozofia care a stat la baza conceptului:

1945 – 1956 – Orientarea spre depănare

Testarea programelor informatice este o activitate care a apărut o dată cu procesul de dezvoltare a acestora. În perioada apariției primelor sisteme informatice – 1945-1956, procesul de testare era în special orientat către componentele hardware ale sistemului, iar defectele din software erau în general considerate ca fiind mai puțin importante. Persoanele care elaborau codul se ocupau și de partea de testare, deși nu o făceau într-o manieră metodică, și denumeau această activitate verificare.

1957 – 1978 – Orientarea spre demonstrație

Pe măsură ce sistemele informatice creșteau în număr, complexitate și cost, procesul de testare a căpătat o importanță tot mai mare. Testarea pe scară largă a devenit necesară datorită creșterea impactului economic pe care defectele nedetectate le puteau avea. De asemenea, persoanele implicate în dezvoltarea de programe informatice au devenit mai conștiente de riscurile asociate cu defectele din programe și au început să pună mai mult accent pe testarea și remedierea defectelor înainte ca acestea să afecteze produsul livrat. În această perioadă, termenii de testare și depanare se suprapuneau și se refereau la eforturile făcute în scopul descoperirii, identificării și remedierii defectelor din sistemele informatice. Scopul procesului de testare era demonstrarea corectitudinii funcționării programului, adică absența erorilor.

1979 – 1982 – Orientare spre defect

Conceptele de depănare și testare devin mai riguros separate o dată cu publicarea de către Glenford J. Myers a lucrării The Art of Software Testing, în 1979. Myers face distincția dintre depanare care este o activitate care ține de dezvoltarea programului și testarea care este activitatea de rulare a unui program cu scopul declarat de a descoperi erori. De asemenea, el susține că în testarea bazată pe demonstrație există pericolul ca operatorul să aleagă în mod inconștient acel set de parametri care ar asigura funcționarea corectă a sistemului, ceea ce creează pericolul ca multe defecte să treacă neobservate. Myers propune în abordarea sa și o serie de activități de analiză și control care împreună cu procesul de testare să crească nivelul de calitate a sistemelor informatice.

1983 – 1987 – Orientarea spre evaluare

În 1983, Biroul Național de Standarde din Statele Unite ale Americii publică un set de practici adresate activităților de verificare, validare și testare a programelor de calculator. Această metodologie, adresată în mod specific instituțiilor americane federale, cuprinde metode de analiză, evaluare și testare care să fie aplicate de-a lungul ciclului de viață al aplicației. Ghidul de bune practici sugerează alegerea unor diverse metode de verificare și validare, în funcție de caracteristicile fiecărui proiect în scopul creșterii calității generale a produsului. În anii '70 nivelul de profesionalism al persoanelor implicate în activitatea de testare a crescut simțitor. Apar posturile dedicate de tester, manager de teste sau analist de teste. Apar de asemenea organizații profesionale ale celor care activează în domeniul testării software, precum și publicații specializate, cărți și articole de specialitate. Mai important, instituțiile americane ANSI și IEEE încep elaborarea unor standarde care să formalizeze procesul de testare, efort concretizat în standarde precum ANSI IEEE STD 829, în 1983, care stabilea anumite formate care să fie utilizate pentru crearea documentației de testare.

1988 – în prezent – Orientarea spre prevenire

Standardele precedente sunt dezvoltate și îmbunătățite începând cu 1987 când IEEE publică o metodologie comprehensivă care se aplică în toate fazele ciclului de viață a programului. Testarea trebuie făcută în toate fazele de lucru, în paralel cu programarea și are următoarele activități principale: planificare, analiză, proiectare, implementare, execuție și întreținere. Respectarea acestei metodologii duce la scăderea costurilor de dezvoltare și de întreținere a unui sistem prin scăderea numărului de defecte care ajung nedetectate în produsul final.

2.2 Selenium Generalități

Selenium a prins viață în 2004, cu ajutorul lui Jason Huggins în timp ce testa o aplicație pentru ThoughtWorks . Acesta și-a dat seama ar fi folositor să scurteze timpii de testare manuală pas cu pas prin aceleași teste făcute automat. A dezvoltat o bibliotecă Javascript , care putea conduce interacțiunile cu pagină web, permițându-i să ruleze din nou în mod automat teste pe mai multe browsere .Această bibliotecă a devenit în cele din urmă Selenium Core, care stă la baza tuturor funcționalităților pentru Selenium Remote Control ( RC ) și Selenium IDE . Selenium RC a fost o invenție foarte importantă , deoarece nici un alt produs nu permitea la acel moment controlul unui browser prin intermediul unui limbaj ales de utilizator.

Chiar dacă Selenium a fost un instrument extraordinar , nu a fost fără dezavantaje. Datorită motorului său de automatizare bazat pe Javascript și a limitărilor de securitate pe care browserele le au în Javascript , au apratut lucruri care nu puteau fi făcute . Mai mult decât atât, aplicațiile web au devenit mult mai puternice în timp , folosind tot felul de caracteristici speciale, au apărut noi browsere, noi tehnologii.

În 2006, un inginer de la Google Simon Stewart a început să lucreze la un proiect pe care la numit WebDriver . Google a fost mult timp un utilizator greu de selenium doar ca testeri au trebuit să jongleze în jurul limitărilor produsului . Simon a dorit un instrument de testare care să comunice direct cu browser-ul folosind metoda " nativă " pentru browser și sistemul de operare , evitându-se astfel restricțiile Javascript. Proiectul WebDriver a început cu scopul de a înlătura punctele slabe ale Seleniumului .În anul 2008 Selenium fuzionează cu WebDriver luând naștere SeleniumWebDriver.

2.3 Selenium RC sau Remote Control și IDE

Selenium RC a fost proiectul principal de selenium pentru o lungă perioadă de timp, înainte de fuziunea WebDriver/Selenium și implicit existenta Selenium 2, cel mai nou și mai puternic tool elenium Core, care stă la baza tuturor funcționalităților pentru Selenium Remote Control ( RC ) și Selenium IDE . Selenium RC a fost o invenție foarte importantă , deoarece nici un alt produs nu permitea la acel moment controlul unui browser prin intermediul unui limbaj ales de utilizator.

Chiar dacă Selenium a fost un instrument extraordinar , nu a fost fără dezavantaje. Datorită motorului său de automatizare bazat pe Javascript și a limitărilor de securitate pe care browserele le au în Javascript , au apratut lucruri care nu puteau fi făcute . Mai mult decât atât, aplicațiile web au devenit mult mai puternice în timp , folosind tot felul de caracteristici speciale, au apărut noi browsere, noi tehnologii.

În 2006, un inginer de la Google Simon Stewart a început să lucreze la un proiect pe care la numit WebDriver . Google a fost mult timp un utilizator greu de selenium doar ca testeri au trebuit să jongleze în jurul limitărilor produsului . Simon a dorit un instrument de testare care să comunice direct cu browser-ul folosind metoda " nativă " pentru browser și sistemul de operare , evitându-se astfel restricțiile Javascript. Proiectul WebDriver a început cu scopul de a înlătura punctele slabe ale Seleniumului .În anul 2008 Selenium fuzionează cu WebDriver luând naștere SeleniumWebDriver.

2.3 Selenium RC sau Remote Control și IDE

Selenium RC a fost proiectul principal de selenium pentru o lungă perioadă de timp, înainte de fuziunea WebDriver/Selenium și implicit existenta Selenium 2, cel mai nou și mai puternic tool Selenium.

Selenium 1 este încă susținut activ (mai ales în modul de întreținere) și oferă câteva caracteristici care nu pot fi disponibile în Seleniul 2 pentru o vreme, inclusiv suport pentru mai multe limbaje (Java, Javascript, Ruby, PHP, Python, Perl și C #) și suport pentru aproape orice browser.

IDE selenium (Integrated Development Environment) este un instrument de prototipuri pentru construirea de scripturi de testare. Este un plug-in Firefox și oferă o interfață ușor de utilizat pentru dezvoltarea de teste automate. IDE Seleniulm are o caracteristică de înregistrare, care înregistrează acțiunile utilizatorului când acestea sunt efectuate și apoi le exportă ca un script reutilizabil într-unul din mai multe limbaje de programare care pot fi executate mai târziu.

2.4 Selenium Webdriver compatibilități

Selenium-WebDriver acceptă următoarele browsere, care împreună cu sistemele de operare sunt compatibile cu:

Google Chrome

Internet Explorer 6, 7, 8, 9, 10 – 32 and 64-bit where applicable

Firefox: latest ESR, previous ESR, current release, one previous release

Safari

Opera

HtmlUnit

phantomjs

Android (with Selendroid or appium)

iOS (with ios-driver or appium)

Selenium este extrem de flexibil. Există mai multe moduri în care putem adăuga funcționalitate pentru scripturile de testare de selenium cât și framework-ului de Selenium pentru a personaliza/tipiza testarea automată. Costumizarea oferă cea mai mare putere a seleniumului în comparație cu alte instrumente de automatizare.

Caracteristica primară a noului Selenium 2.0 este integrarea API WebDriver. WebDriver este conceput pentru a oferi o interfață programare mai simplă mai concisă, față de limitările în API ale Seleniu-RC. Seleniu-WebDriver a fost dezvoltat pentru a sprijini mai bine pagini web dinamice în care elemente ale unei pagini pot fi modificate fără ca pagina în sine să fie reîncărcata. Scopul WebDriver este de a furniza un API orientat- pe obiect bine conceput, care oferă suport îmbunătățit pentru probleme moderne avansate de testare web-app.

Fig.2.2 Compatibilitate Selenium-browser

Selenium-WebDriver face apeluri directe către browser, folosind suportul nativ pe care fiecare browser îl are pentru automatizare. Modul în care sunt realizate aceste apeluri directe, precum și facilitățile pe care le susțin depinde de browser-ul pe care îl utilizăm.

Spre deosebire de Selenium-RC, acest lucru este destul de diferit ca abordare. Selenium-RC lucrează în același mod pentru fiecare browser acceptat. Era injectat un "javascript” cu funcții în browser la momentul în care browser-ul era încărcat și apoi erau utilizate de activarea JavaScriptului. WebDriver nu folosește această tehnică , aceasta conduce browser-ul cu ajutorul suportului de automation construit în browser.

2.5 WebDriver și Selenium-Server

În funcție de necesități WebDriver se poate folosi împreună cu Selenium Server. Dacă va fi folosint doar API-ul de WebDriver nu este nevoie de Selenium-Server. În cazul în care browser-ul și testele vor rula pe aceeași mașină, și testele utilizează doar API-ul WebDriver, atunci nu este nevoie de Seleniu-Server; WebDriver va rula direct pe browser.

Totuși există câteva motive, pentru a folosi Selenium-Server cu Selenium-WebDriver:

Se folosește Selenium-Grid pentru a distribui testele pe mai multe mașini sau mașini virtuale (VMS).

Dacă se dorește conexiunea la o mașină de la distanță (VM), care are o anumită versiune de browser care nu este pe mașina dvs. curentă.

Nu sunt utilizate legăturile Java (de exemplu, Python, C #, sau Ruby), și se dorește folosirea driverului HtmlUnit

2.6 Webdriver localizarea elementelor

Cu ajutorul Web driver putem localiza elemente după :

ID

Acesta este modul cel mai eficient și preferat pentru a localiza un element.

IWebElement element =driver.FindElement(By.Id("NumeID")

Numele Clasei

"Clasa", în acest caz se referă la atributul pe elementul DOM. De multe ori, în practică, există multe elemente DOM cu același nume de clasă.Putem avea o listă de elemente cu aceeași clasă.

IList<IWebElement> cheeses = driver.FindElements(By.ClassName("Clasa"));

Tag Name

După numele etichetelor (tag-urilor).

<input name="tagName" type="text"/>

IWebElement tagNameul= driver.FindElement(By.Name("tagName"));

Link Text

Găsește elementul de link-uire cu textul vizibil ce se potrivește.

<a href="http://www.google.com/search?q=etc ">LinkText</a>>

IWebElement LinkText= driver.FindElement(By.LinkText("LinkText "));

Parțial Link Text

Găsește elementul partual de link-uire cu textul vizibil ce se potrivește.

a href="http://www.google.com/search?q=cheese">search for LinkText</a>>

IWebElement LinkText = driver.FindElement(By.PartialLinkText("LinkText"));

JavaScript

Se poate executa javascript arbitrar pentru a găsi un element și, atâta timp cât vă veți întoarce un element DOM, acesta va fi convertit automat la un obiect de tip WebElement recunoscut de webdriver.

WebElement element = (IWebElement) ((IJavaScriptExecutor)driver).ExecuteScript("return $('.cheese')[0]");

IList<IWebElement> labels = driver.FindElements(By.TagName("label"));

IList<IWebElement> inputs = (IList<IWebElement>) ((IJavaScriptExecutor)driver).ExecuteScript(

"var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +

"inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels)

CSS

La fel cum sugerează și numele, este o strategie de localizare cu ajutorul Cascade Style Sheet.

Nu toate browserele au fost create la fel, unele CSS-uri care ar putea funcționa într-o versiune de browser poate să nu vor functineze în alta.

<div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>

________________________________________________________________

IWebElement cheese = driver.FindElement(By.CssSelector("#food spân.dairy.aged"));

XPATH

La un nivel ridicat, WebDriver utilizează capacitățile XPath native un browser de ori de câte ori este posibil. Pe browserele care nu au suport nativ XPath, webdriver folosește propria implementare.

<input type="text" name="example" />

<INPUT type="text" name="other" />

IList<IWebElement> inputs = driver.FindElements(By.XPath("//input"));

2.7 Seleium WebDriver DRIVERS

FirefoxDriver

Controlează browser-ul Firefox cu ajutorul unui plug-in Firefox. Profilul Firefox, care este utilizat este nou și diferit de cel instalat pe mașină acesta include numai Selenium WebDriver.xpi (plug-in). Driver-ul Firefox este capabil de a fi rulat și testat pe Windows, Mac, Linux.

Mod de folosire:

IWebDriver driver = new FirefoxDriver();

Chrome driver

Este menținut / susținut de proiectul Chromium. WebDriver lucrează cu Chrome prin binar chromedriver, este nevoie atât de chromedriver cat și de o versiune a browser-ul Chrome instalata. Chromedriver trebuie să fie plasat undeva pe calea sistemului pentru ca WebDriver să-l descopere în mod automat. Browser-ul Chrome în sine este descoperit de chromedriver în calea de instalare implicită.

Mod de utilizare:

IWebDriver driver = new ChromeDriver();

2.8 Selenium Waits (timpi de așteptare)

2.8.1 Explicit wait

Asteptarea explicita este codul definit pentru a astepta ca o anumită condiție să apară înainte de a trece mai departe în cod. In cel mai rău caz acest lucru este Thread.sleep (), care seteaza o perioadă de timp exact să se aștepte. WebDriverWait în combinație cu ExpectedCondition este o modalitate pentru aștepta doar atâta timp cât este necesar.

IWebDriver driver = new FirefoxDriver();

driver.Url = "http://somedomain/url_that_delays_loading";

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));

IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>

{

return d.FindElement(By.Id("someDynamicElement"));

});

Aceasta așteaptă până la 10 secunde înainte de a arunca o TimeoutException sau în cazul în care gaseste elementul il va returna in mai putin de10 secunde. WebDriverWait implicit cheama ExpectedCondition la fiecare 500 milisecunde până se întoarce cu succes. O revenire de succes este de tip ExpectedCondition un Boolean cu valoare adevărată / falsa sau nul pentru toate celelalte tipuri de ExpectedCondition.

2.8.2 Implicit wait

O așteptare implicită spune WebDriver-ului sa caute la un anumit interval in DOM pentru a gasi un element sau elemente dorite, dacă acestea nu sunt disponibile imediat. Setarea implicită este 0. Odată setat este setat pentru durata de viață a instanței obiect WebDriver.

WebDriver driver = new FirefoxDriver();

driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));

driver.Url = "http://somedomain/url_that_delays_loading";

IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

2.9 De ce să automatizăm?

Testarea software este o activitate esențială dar și scumpă și laborioasa în același timp, de aceea automatizarea oricărei faze a procesului poate reduce timpul de testare pe termen lung poate scădea costurile totale ale activității de testare. Există mai mulți factori luați în considerare atunci când se planifica automatizarea de testare software. Automatizarea schimba complexitatea de testare și organizarea testelor de la proiectare până la punerea în aplicare și executarea acestora. În general are un impact vast asupra organizației de la sarcinile îndeplinite, abordări de testare, și chiar caracteristici de produs. Exista părți tangibile cât și intangibile, precum și mituri răspândite cu privire la avantajele și capacitățile testării automatizate. Este important să se înțeleagă într-adevăr costurile și beneficiile potențiale înainte de a întreprinde un fel de schimbare în automatizare, cel puțin pentru a planifica în vederea obținerii unui randament crescut. 

Efectele organizatorice includ lucruri cum ar fi competentele necesare pentru a proiecta și implementa teste automate, instrumente de automatizare și medii de automatizare. Dezvoltarea și întreținerea de teste automate este destul de diferită de testele manuale. Se schimbă paleta de competente, abordările de testare, precum și testarea în sine, când automatizarea este instalată. Automatizare are potențialul de a schimba produsul testat și  procesele utilizate pentru dezvoltare și punere în producție. Aceste efecte au componente pozitive și negative, care trebuie să fie luate în considerare.

  Testarea software este, de asemenea, foarte importantă, deoarece:

30% din timp este pierdut cu corectarea defectelor

26% dintre proiecte sunt livrate cu întârziere

10% dintre companii plătesc penalități pentru întârzieri în livrare

Testare Software automată economisește timp și bani

Testare Software automată îmbunătățește precizia

Testare Software automată crește aria de testare

Testare Software automată face ceea ce testele manuale nu fac

Testare Software automată ajuta dezvoltatorii și tester-ii

Testare Software automată îmbunătățește moralul echipei

Unul din cele mai importante motive pro automatiare este testarea de regression.Se întâmpla adesea că o bucată de cod care funcționa bine azi să nu mai funcționeze mâine iar aici intervine regression testing-ul în ajutor.Majoritarea dezvoltării soft se îndreaptă spre Agile ceea ce înseamnă lucrul în iterații și adăugare de noi îmbunătățiri programelor soft periodic la perioade scurte de timp.Pentru că lucrurile se schimba atât de rapid trebuie să avem un regression foarte bun care poate fi realizat prin automatizare astfel vechiile funcționalități pot fi verificate într-un mod rapid și eficient.

Dacă se folosește un framework bun se poate ajunge la cazul în care testele să fie scrise cu o foarte mare rapiditate și cu foarte puține linii de cod.Iar aceste partru cinci linii de cod să testeze câteva sute sau mii de linii de cod din producție.Blackbox automation-ul aduce un avantaj în acoperirea une bucăți mari din sistem cu puține linii de cod.

2.10 BlackBox automation

Vom urmări pe scurt tipurile de teste automate și diferențele care sunt între diferitele tipuri de testare automată. Primul tip de testare automată este de unitate de testare (unit testing).Unitate de testare este atunci când testarea se face la nivel de unitate. De obicei, acest lucru înseamnă că se testează o anumită clasă și se face în mod izolat. Majoritatea timpului unit testing-ul este făcut de către developeri pe măsură ce scriu codul.Test Driven developement este practică de a creea întâi unit testele iar mai apoi codul de producție.

Integration testing testarea de integrare este cu strat mai sus în ierarhia testării.În loc să testezi individiual unități testarea de integrare testează cum interactionaza acele unități între ele.Integration testing asemeni unit testing folosește mai mult partea de cod și nu cea de interfața a utilizatorului.

Dacă urcăm cu un strat mai sus ajungem la ceea ce putem numi BlackBox Automated Testing.În această categorie putem introduce System testing, User acceptance testing, Acceptance testing .În acest caz nu există acces la cod asemeni metodelor WhiteBox prezentate mai sus(Unit testing și Integration testing).Testele automate sunt scrise pentru a interacționa asemeni unui utilizator normal.

Fig 2.3 Straturi testare

2.11 Greșeli comune în crearea framework-ului de testare automată

În majoritatea cazurilor când cineva începe să automatizeze teste se ajunge într-un punctul în care se folosesc tool-uri pentru înregistrare.Această abordare pare la prima vedere

una foarte bună deoarece este foarte rapidă.Însă ceea ce se întâmplă în majoritatea cazurilor este că ceva se va schimba în aplicație și testul va pica. Fiind un test înregistrat în multe cazuri singura opțiune este să îl re-inregistrezi sau să îl editezi manual. Problema principală este ca toate aceste mici reparații ale testcase-urilor se vor înmulții pe măsură ce codul se schimbă ajungându-se la un momentdat să fie atât de dese încât nu se mai merită costul de a învești în teste automate. Creearea unui Framework poate rezolva aceste probleme.Un alt mare minus legat tot de înregistrarea testcase-urilor este ca atunci când o schimbare are loc în aplicație de exemplu pe interfața utilizatorului există și o schimbare de funcționalitate care influențează mai multe teste toate depinzând prin diferite aspecte de interfață utilizatorului.Toate aceste teste vor trebuii rescrise (înregistrate) individual .Această problemă poate fi rezolvată prin creearea unu buffer între aplicație și test cu ajutorul unui framework.

Majoritatea testelor automate sunt scrise în limbaje de programare de nive înalt C#, Java, Ruby iar de multe ori aceste asunt scrise asemănător unui cod normal dintr-o aplicație, lucru care ajunge să fie foarte complicat pentru cineva care nu înțelege foarte bine programarea.De multe ori testele sunt scrise de developeri și sunt lăsate testării pentru mentenanța.Pentru că testele sunt scrise asemeni codului dintr-o aplicație normală aceastea sunt greu de înțeles și de menținut calitatea lor scăzând. De aceea testele ar trebui scrise într-un mod ușor de înțeles mult simplificat.

  2.12 Abordarea creării unui automation framework

Framework-ul să fie separat adică să nu avem test automate care accesează în mod direct aplicația noastră web deoarece dacă se schimbă ceva în aplicație toate testele care implica această schimbare vor pica .Ca urmare fiecare test va trebui updatat individual.

În schimb dacă creem un framework de automation care va sta între aplicație și teste de fiecare dată când un test se va executa va chema o metodă din framework care va știi cum să facă acțiunea. Dacă ceva se shimba în aplicație doar framework-ul va și afectat de schimbare astfel că dacă avem 20 de teste care folosesc o metodă din framework nu vom fi nevoiți să facem schimbarea în 20 de locuri ci doar în framework.

O altă abordare bună este aceea de a avea teste simple o granulare cât mai bună a testelor va duce la o mentenanță mai ușoară a acestora fiind ușor de înțeles.

Un alt factor care ne va ajuta în creearea framework-ului este de implica testele noastre în creerea framework-ul bineînțeles după ce avem o bază funcțională a acesutia.Vom avea o abordare asemănătoare test driven developemt adică vom creea întâi testele iar după vom scrie codul pentru framework ceea ce va duce la redactarea unor teste simple și ușor de înțeles.

Fig 2.4 Stratificare Framework

2.13 Straturile unui framework

Un lucru inportant în crearea și designul unu automation framework este modul în care acesta este stratificat. Avem testele care folosesc framework-ul și framework-ul care folosește Selenium. Dar și framework-ul trebuie împărțit în mai multe straturi, bineînțeles că aceasta stratificare depinde în o foarte mare măsură de aplicația aflată sub test însă unele straturi pot fi folosite pentru majoritatea aplicațiilor. Putem avea un strat workflow în care vom avea lucruri mai mari decât o pagină cum ar fi de exemplu creearea unui nou client.Vom chema acest workflow în teste pentru a creea un nou client.Un alt strat poate fi cel al păgânilor iar cel mai probabil wrokflow-ul v-a fi dependent de pagini. Acest strat va defini funcționalități de pe o singură pagină. Un alt strat poate fi navigare unde pot fi centralizate toate elementele comune navigării prin aplicație.

Important este să ținem seama de straturile framework-ului de automation când îl creem și să avem o arhitectură în minte când facem designul .De asemenea trebuie să fim atenți și la modul în care straturile comunică între ele pe măsură ce acestea se înmulțesc.

Scopul principal al frameworkului de automation este ușurința cu care acesta poate fi folosit .

2.14 Reguli ce ajută la creearea unui framework

Testele nu ar trebuii să declare variabile. Nu dorim ca persoana care creează testele să creeze variabile totuși este o regulă greu de menținut. Testele nu ar trebuii să folosească “new” keyword pentru a creea obiete noi. Trebuie să încercăm să facem statice metotele. Browserul sau structura DOM nu trebuie expusă testelor sau să fie manipulate de teste. Numărul de paramaetri pentru call-urile de API trebuie să fie cât mai redus când este posibil. Nu dorim să avem metode cu un număr mare de parametri , numărul acestora ar trebuii să fie cât mai mic.

2.15 Domain Specific Languages

Conceptul de DSL( Domain Specific Languages) este foarte important în momentul în care implementezi un framework de automation pentru că DSL este ceva ce va fi implementat ulterior. Domain Specific Language după cum îi spune și numele reprezintă un limbaj specific pentru un anumit domeniu.Un exemplu bun este limbajul SQL care ste un limbaj specific domeniului bazelor de date. DSL sunt folositoare pentru că ne permit să exprimăm soluții pentru probleme sau algoritmi într-un mod croit pentru un domeniu specific unei anumite probleme. Conexiunea cu automation-ul este că testele care sunt scrise în concordanță cu frameworkul folosesc DSL pe care noi îl definim prin clase metode și le expunem din framework. Când sunt scrise teste folosind frameworkul acestea ar trebui să scrie teste care își asumă domeniul aplicație care este testată rezultând un test mai simplu și mai ușor de înțeles.

2.16 Tipuri de DSL

Există două tipuri de bază pentru DSL.Primul este internal DSL unde folosim limbajul de programare utilizat pentru framework.Nu creem un nou limbaj ci doar o sintaxe în actualul limbaj de programare care vor fi folosite de teste.External DSL acesta este un domain specific language în adevăratul sens al cuvântului.Acesta poate avea sintaxe de genul LoginPage, DoAction Login with, UserName, Password, EndAction.Creearea acestui tip de limbaj este destul de laborioasa, practic trebuie să creezi un fel de interpretor sau parser care să traducă în calluri spre framework sintaxă.Chiar dacă este mai greu de creeat cu ajutorul unui DSL extern este foarte ușor să creezi testcaseuri.

 DSL-ul este important pentru că poate fi folosit de persoane care nu au background tehnic.Un tool care poate fi folsit pentru a creea un asemenea lumbaj este ANTLR , acesta este foarte puternic și poate ajuta la creearea sintaxei și la conectarea sintaxei la elementele de logică.O strategie bună este să constuiesti limbajul DSL peste API-ul de framework.

2.17 Rularea testelor

Unul dintre ultimele lucruri la care trebuie să ne gândim înainte să creem un framework este cum vom rula testele. Este important să luăm în considerate acest aspect încă de la început deoarece poate influența cum vom creea arhitectura pentru framework-ul de automation. Majoritatea testelor automate black box vor fi rulate ca parte a unui build central dar și local pe mașinile unde se dezvoltă. Este important să ținem seama cum putem face că testele să poată fi rulate în ambele scenarii.Dacă testele nu sunt ușor de rulat cel mai probabil acestea nu vor fi rulate. Ideal este că dezvoltatorii framework-ului să poată rula cu ușurință testele local. Acest lucru previne și da posibilitatea dezvoltatorilor să poată testa codul inante de a îl îngloba în pachetul de pe server.Bineînțeles pentru a putea rula testele pe un server avem nevoie de un testdriver.

2.18 Drivere de test

Ca și exemplu de driver pentru a rula testele pe server probabil unul dintre cele mai commune modalități de a rula teste automate blakbox este folosirea unui unit testing framework cum ar fi de exemplu JUnit dacă folosim Java sau NUnit dacă folosim C# sau oricefel de framework de unit testing. Desigur se poate creea orice fel de driver se dorește dar folosind unit testingul este o metodă rapidă de a îți putea rula testele.Un al lucru de luat în considerare în momentul în care vrei să rulezi teste este faptul că teste au nevoie să raporteze rezultatele.Cum o să fie raportate testele este foarte important doarece acest rezultat confirma sau infirma faptul că testul a trecut cu succes sau faptul că testul nu a fost executat cu success.În cazul în care testul are un rezultat negativ o bună logare a pașilor executați ne poate ajuta să ne dăm seama rapid de locul în care trebuie investigat pentru a remedia problema.Un logging însoțit atât de logare a exceptilor dar care poate să facă și o poză a aplicației în momentul în care excepția este aruncată îmbunătățește timpul de debugging și implicit timpul de remediere al situației.

2.19 Greșeli comune în designul testelor

Una dintre cele mai comune greșeli pentru multe teste automate este că acestea nu eșuează (fail). Această problemă este foarte importantă pentru că dacă nu avem teste care eșuează toată testare este complet inutilă. Este o pierdere de vreme în investirea de timp pentru creearea testelor și framwork-ului.Scopul automatizării este să găsim cât mai multe probleme ale sistemului dacă acestea există așa că trebuie să ne asigurăm că testam un anumit lucru care fie se întâmplă fie nu se întâmplă iar testul nostru trebuie să aibă abilitatea de a își da seama dacă condiția se îndeplinește sau nu, dacă este cazul să raporteze eroarea Cel mai bun mod în a te asigura că testele sunt eficiente este să testăm că în cazul neîndepliniri condiției acestea vor eșua. Dacă nu testam faptul că testul ar eșua și nu constatăm că raportează faptul că condiția nu este îndeplinită este ca și cum am creea un produs care presupunem că va funcționa.

Sunt câteva medote prin care ptem face că testele noastre să eșueze dar ceea ce dorim este să ne asigurăm că în cazul în care codul este greșit testul nostru să poată sesiza acest lucru și să îl indice.

2.20 Automatizarea lucrurilor grele

Un lucru care poate cauza eforturile de automation să fie inutile este să creezi teste care sunt foarte greu de automatizat.Un exemplu ar fi un plug în flash dintr-o aplicație care este folosit într-o anumită zonă a acesteia.Totuși cu Selenium sau cu un alt tool de automation se poate automatiza cu destul de mare ușurință și Flash.Un alt exemplu poate fi un output care este greu de verificat.Să zicem că nu putem face un assert pentru o imagine care este produsă de un website.Ar trebuii să comparăm două imagini ceea ce va implica creearea de logică destul de dificil de implementat.În aceste cazuri trebuie să fim pragmatici, s-ar putea să automatizăm totul sau s-ar putea să nu putem automatiza totul fie să găsim portițe de compromis (workaroud).Dar să revenim ceea ce este important e să evaluăm dacă merită efortul depus pentru a automatiza un anumit flow.Dacă chiar vrem să automatizăm ceva cu un grad de dificultate ridicat putem să facem acest lucru în momentul în care scenarile de bază sunt acoperite și nu avem ceva mai prioritar.

2.21 Errori VS Eșecuri

Errors V.S. Failures este un subiect controversat în ceea ce privește automatizarea.A face diferența dintre erroare și failure este foarte important . Ceea ce se întâmplă des în soluțiile de automation este că testele vor pică și dese ori vor pica din cauză că avem ceva greșit în framework sau aplicație să stricat într-un mod în care funcționalitatea de bază este afectată cum ar fi un flow de navigație.

Testele trebuie să pice doar pentru că condiția dată la creere nu a fost îndeplinită și că ceea ce încerci să testezi nu funcționează. Nu vrem că testul să pice din cauza unei erori dacă poate să testeze lucrul care este urmărit spre a fi testat. De câte ori testul pică din cauza acestor tipuri de erori testul este arătat eronat că și fail (picat).O modalitate de a evita lucrul acesta este să creem un cod în framework care să facă față unor asemenea cazuri și să nu indice testul fail (picat) dar să noteze și erorile pe care le întâlnește.Această distincție este inportanta pentru a ne putea da seama ce se întâmplă defapt în momentul testării și care este cauza eșuării.

2.22 Integrare continuă

Un alt topic inportant pentru orice framework de automation este continous integration (integrarea continuă). Multe medii de dezvoltate folosesc un fel de integrare continuă pe server sau pe o mașină care va creea un pachet nou la un anumit timp. Pe orice tip de server este important să avem un plan și să fim consegventi în urmărea acestuia. S-ar putea să nu rulăm toate testele automate după fiecare pachet sau s-ar putea să nu îl rulăm de fiecaredata dar probabil vorm vrea să rulăm testele la un anumit interval. Există câteva soluții pentru a rula testele una ar fi să avem soluții paralele și să rulăm de fiecare dată testele pe una dintre soluții.O altă soluție este să rulăm testele noaptea.Oricare din variantele acestea le-am alege trebuie să avem un program bine pus la punct.

Fig 2.5 Exemplu de integrare continua

2.23 Scalarea

Orice tool de automation se va lovi inevitabil de problema scalari.Sunt multe probleme ce pot să apară în această situație.De exemplu ce se întâmplă când testele încep să ia foarte mult timp să se execute pentru că sunt foarte multe teste ce trebuie rulate iar rularea acestora în mod liniar ar putea dura de la câteva ore la zile.În acest punct fie încerci să rulezi testele în paralel fie le împărți în bucăți ce vor fi rulate în perioade diferite.

Metoda divizării testelor este una destul de primitivă, dacă avem 100 de teste putem rula 50 de teste pe un pachet și 50 pe următorul pachet.Această metodă salvează timp și are o acoperire relativ bună.În cazul rulării testelor în paralel putem avea mai multe abordări una este să folosim mai multe threaduri dar făcând acest lucru va trebui să avem grijă ca testele să nu interfereze între ele.O altă metodă este să împărțim testele și să le rulăm pe diferite mașini sau instante astfel îmbunătățim mult timpul necesar rulării.Cu cât avem mai mulți agenți cu atât crește rapiditatea rulării testelor.

Din fericire există câteva companii diferite și servicii care pot să ne facă viața mai ușoară în ceea ce privește rularea testelor în paralel.Practic toate testele pot fi rulate în Șauce Labs sau un serviciu similar .Șauce Labs este probablil unul dintre cele mai folositoare servicii pentru Selenium unde poți rula testele în Cloud.Poți rula testele pe orice combinație de browsere și platforme.

2.24 Lucrul în metodologia Agile

În multe cazuri dezvoltare se face în metodologia Agile.Se folosește Scrum sau o altă formă de Agile care câteodată nu funcționează foarte bine cu testarea și asigurarea calității.O metodă bună de a rezolva această problemă este că testele tale automate să facă parte din done criteria.Când începem să lucrăm la backlog sau la un story pentru o iterație anume din ciclul Agile vom avea grijă ca creearea de teste automate să facă parte din backlog și trecerea testelor automate cu succes să facă parte din done criteria.Deci înainte ca un story aume să fie considerat făcut trebuie să treacă toate testele automate ce îi sunt asociate. După ce acestea trec testele sunt mutate în suita de regression.

Această metodă poate fi puțin mai greu de implementat și poate încetini mersul lucrurilor la început însă odată acomodați cu ea devine foarte eficientă.Dacă scrierea testelor ia foarte mult timp și încetinește întregul proces foarte tare este posibil ca acest gen de abordare să fie repins și să fie nevoie de o nouă abordare.

Fig 2.6 Ciclul Agile

2.25 Testarea pe diferite versiuni de browsere

De multe ori eforturile de automation sunt blocate de dorința de a testa pe toate versiunile și tipurile de browsere întreaga suită de teste. Nu este necesar să testăm pe toate versiunile/browserele întreaga suită de teste este suficient să testăm pe un singur browser și să rulăm doar niște smoke teste pe restul versiunilor. De exemplu 4 ore de teste automate pe 10 tipuri de browsere ar rezulta în 40 de ore de testing așa că realizarea regressionului pe un singur browser și doar un smoke test pe restul face sens.Majoritatea testelor nu vor testa capabilitățile browserului ci funcționalități ale sistemului care nu se vor schimba de la browser la browser.

Ocazional poate unele mici probleme vor resusi să se strecoare dar cea mai mare parte a efortului care l-ai petrece testând complet fiecare browser sau combinație de sistem de operare cu browser versus beneficile pe care le avem neruland toată suită de teste sunt foarte mici.

III IMPLEMENTAREA SOLUȚIEI ADOPTATE ȘI REZULTATE EXPERIMENTALE

3.1 Generalități implementare

Pentru realizarea aplicație respectiv a frameworkului să folosit Visual Studio C# împreună cu Selenium Webdriver. Aplicația este la baza de tip desktop dar cu ajutorul Seleniumului acesta reușește să acceseze web-browserele.Pentru proiectul de fată s-au folosit doua drivere pentru a expune browsing-ul un driver pentru Firefox care vine implicit odată cu Webdriverul și un driver de Google Chrome.

Integrarea Selenium Webdriver în soluția noastră de automation se face prin referentierea librăriilor Selenium de către proiectele noastre prin managementul de pachete nuget prin căutarea acestora online.(Fig 3.1)

Fig 3.1Integrare clase Selenium

Soluția este formată din patru proiecte AutomationTests For Mobile Sites unde avem construită interfața utilizator, Framework unde avem scheletul propriuzis al aplicației, Services unde putem adăuga diferite servicii pentru a interacționa cu test cașeurile noastre, și nu în ultimul rând TestCases unde scriem testele propriuzise.Pentru logare a informațiilor la rularea testelor folosim log4net și o serie de capturi ale ecranului pentru a furniza imagini cu locul în care testul întâmpina probleme.

Testacase-uri care au fost creeate au avut ca subiect testarea unor aplicații de tip mobile web, framework-ul fiind capabil să susțină asmenea tipuri de aplicații da nu numai acestea, se pretează la fel de bine și pentru aplicații web de tip desktop.

Versatilitatea frameworkului este dată în principal de Selenium dar și de limbajul de programare ales.

Fig 3.2 Formatul proiectelor din soluție

Aplicațiile pe care se execută testele automate sunt m.bwin.com, m.bwin.be, m.partypoker.com, m.partycasino.com. Ca o scurtă descriere acestea au secțiuni de pariuri sportive, jocuri de casino, poker, parte de cont al utilizatorului.Testele efectuate se bazează

în principal pe zona de creeare a contului și zona de testare a jocurilor.

3.2 Interfața Framework-ului

După cum aminteam mai devreme proiectul este unul de tip desktop asemenea find și interfața. Teste pot fi rulate în mod direct din interfață grafică a soluției .(Fig 3.3)

Fig 3.3 Interfața pentru rularea testelor

În pratea stângă a interfeței avem testcase-urile disponibile pentru a fi rulate acestea sunt prezentate sub forma arborescenta asemeni structurii de fișiere din proiectul Testcases.Fiecare clasă din proiectul Testcases reprezintă un nume de testcase.Pentru a putea fi rulate și pentru a fi prezente în structura noastră fiecare metodă de start a clasei din care apatine testcase-ul este decorată cu un atribut [Mobile Test Case] care face că testcase-ul să devină vizibil pe interfața.

Pe partea cetrala avem butonul de rulare al testelor urmat de o listă cu mediul în care dorim să rulăm testul site-ul pe care dorim să rulăm testul și nu în ultimul râd limbă pe care dorim să rulăm testul. Putem alege să rulăm testul, limba, site-ul, mediul prin intermediul unror checkbox-uri.

În partea stângă avem poate cea mai importantă parte a framework-ului partea de logare a rezultatelor unui test. În cazul în care acesta trece cu succes vom avea afișat numele testului însoțit de textul „Succes” pe un fundal verde. Acest raport se poate și expanda pentru a vedea ce informații conține.(Fig 3.4)

Fig 3.4 Testcase cu rezultatul “Success”

În cazul în care aplicația nu trece cu succes testul vom avea afișat numele testului însoțit de textul „Failed” pe un fundal roșu. De asemenea și acest raport se poate și expanda pentru a vedea ce informații conține.(Fig 3.5)

Fig 3.5 Testcase cu rezultatul “Failed”

Aceste informații sunt logata cu ajutorul log4net și sunt citite din un fișier text care poate și accesat și separat în folderul logs din aflat în folderul debug al proiectului unde se afla interfața.

Logging.log.Info(“Begin test”);

Logging.log.Error(“Object Not Found”);

Pe lângă această logare sub formă de text mai folsim și o logare prin intermediul screen-shoturilor (instantanee ale monitorului).Acestea pot fi accesate doar urmad o rută asemănătoare cu cea a fișierelor text de unde se citește logul , folderul ScreenCapture aflat în folderul debug al proiectului unde se afla interfața.Pe lângă numele capturii se mai adăugă automată dată și ora la care aceasta a fost făcută.Vom vedea mai multe detalii ale implementării când vom vorbi despre proiectul Framework.

ScreenCapture.MakeScreenShot("Screenshot Name");

Modul în care știm ce este selectat din interfața este dată de următoarea bucată de cod:

private List<string> GetAllEnvironments()

{

List<string> environments = new List<string>();

foreach (object itemChecked in CLB_Environment.CheckedItems)

{

if ("ALL" != itemChecked.ToString())

{

environments.Add(itemChecked.ToString());

}

}

return environments;

}

Un cod asemanartor se folosește și pentru site-ul (Label-ul) selectat.În cazul limbii din cauză că pentru a forma url-ul de unde pormin aplicația folosim însuși valoarea check box-ului iar prescurtări ale limbii cum ar fi : ru, el, de etc.; nu sunt foarte ușor de urmărit putând apărea greșeli de interpretare suntem nevoiți să folosim o sintaxă care să conțină în plus față de cea anterior prezentată un switch case.

private List<string> GetAllLanguage()

{

List<string> language = new List<string>();

foreach (object itemChecked in CLB_Language.CheckedItems)

{

if ("ALL" != itemChecked.ToString())

{

switch (itemChecked.ToString())

{

case "English":

language.Add("en");

break;

etc…

case "Portuguese":

language.Add("pt");

break;

default:

break;

}

}

}

return language;

}

După cum aminteam la început pentru a marca testele cu scopul de a fi indexate în structura arborescentă din stânga interfeței grafice și implicit pentru rularea acestora vom decora metodele sau metodă de start ce conține test case-il cu un atribut numit [Mobile

Testcases], modul în care acesta funcționează poate fi observat în proiectul în care este situată interfața.

List<MethodInfo> methods = testCasesAssembly.GetType(str).GetMethods().ToList();

foreach (MethodInfo methodinfo in methods)

{

List<Object> myAttributes =methodinfo.GetCustomAttributes(false).ToList();

foreach (Object obj in myAttributes)

{

if (obj.GetType().Name.Equals("MobileTestCase"))

{

parentNode.Nodes.Add(methodinfo.Name, methodinfo.Name);

}

}

Metoda care se ocupă cu logarea și afișarea logurilor are doi parametri unul methodinfo iar celelalt success care indică dacă testul returnează fals sau true ca urmare acest ultim parametru decide statusul testului și implicit colorează cu verde dacă trestul trece sau cu roșu dacă acesta nu trece întregul log .

private static string GetTestCaseReportFromLogFile(MethodInfo methodinfo, bool success)

{

var fileContent = string.Empty;

using (var stream = new FileStream(

Environment.CurrentDirectory + @"\logs\" + methodinfo.Name + ".txt",

FileMode.Open,

FileAccess.Read,

FileShare.ReadWrite))

{

byte[] byteArray = new byte[1024];UTF8Encoding tempText = new UTF8Encoding(true);

while (stream.Read(byteArray, 0, byteArray.Length) > 0)

{

fileContent += tempText.GetString(byteArray);

}

}

string toggleInlineFunction = "if(document.getElementById('" + methodinfo.Name + "Details').style.display=='none'){document.getElementById('" + methodinfo.Name + "Details').style.display='block';}else{document.getElementById('" + methodinfo.Name + "Details').style.display='none';}";

string txt = "<li style='background=" + (success ? "green":"red") + "' onclick=\"" + toggleInlineFunction + "\">" + methodinfo.Name + " – " + (success? "Succes" : "Failed");

txt += "<div style='display:none' id='" + methodinfo.Name + "Details' ><pre>" + fileContent + "</pre></div></li>";

return txt;

}

Pe lângă afișarea propriu-zisă în interfața în partea stângă unde se afla raportarea se creează un fișier text și un fișier HTML unde se afla logarea.

Metoda următoare este folosită de proiectul în care se afla interfața pentru a popula structura arborescentă din partea stângă a interfeței utlilizator.În o primă fază excludem din lista folderul TestCasesHelper care are rolul doar de a oferi susținere în crearea testelor .

private void FillTreeView()

{

List<string> list = testCasesAssembly.GetTypes().Select(t => t.FullName).Where(t => !t.Contains("TestCasesHelper")).Distinct().ToList();

foreach (string str in list)

{

TreeNode parentNode = TestcaseTree.Nodes[0];

string[] parts = str.Split('.');

for (int i = 0; i < parts.Length; i++)

{

TreeNode[] node = TestcaseTree.Nodes.Find(parts[i], true);

if (node.Length == 0)

{

parentNode = parentNode.Nodes.Add(parts[i], parts[i]);

}

else

{

parentNode = node[0]}

}

// insert all functions with [MobileTestCase] from this file

List<MethodInfo> methods = testCasesAssembly.GetType(str).GetMethods().ToList();

foreach (MethodInfo methodinfo in methods)

{

List<Object> myAttributes = methodinfo.GetCustomAttributes(false).ToList();

foreach (Object obj in myAttributes)

{

if (obj.GetType().Name.Equals("MobileTestCase"))

{

parentNode.Nodes.Add(methodinfo.Name, methodinfo.Name);

}

}

}

}

După ce aducem în structura arborescentă toate directoarele (clasele) din proiectul Testcases parcugem lista pentru a vedea care dintre metode este decorată cu atributul [MobileTestCase] pentru a putea inițializa testele și a le rula.

3.3 Proiectul Framework

În acest proiect se afla defapt întreaga putere a frameworkului propriu zis de aici și numele dat acestei părți din soluție.Este locul în care Selenium Webdriver este integrat în framework.Tot aici are loc și împărțirea proiectului aflat sub test în diferite secțiuni cum ar fi zone ale aplicației.Metoda aleasă de granulare a aplicației aflată sub teste în cazul nostru site-uri de pariuri este următoarea: impărțirea este făcută în zone cum ar fi casino , pariuri sportive , parte de portal și poker. La rândul lor aceste zone sunt împărțite în pagini ce aparțin sectoarelor respective.

Pe lângă această împărțire amintită mai sus avem și o zonă comună care este folosită de toate zonele aplicației sau marea majoritate a acestora.

Fig 3.6 Proiectul Framework

În această zonă comună avem fișiere care conțin constante , elementele de selenium transformate în metode C#, partea de logging , partea de screen capture etc.Una din cele mai importante clase case se află în acest fișier cu scop comun este clasa Base din care se moștenesc toate acțiunile Selenium Webdriver către secțiunea proiectului TestCases.
Dacă tot suntem la această zonă a proiectului în următoarea parte vom prezenta puțin mai detaliat principalele zone comune.

SeleniumWrapper.cs conține principalele caracteristici ale Webdriver-ului transformate în metode specifice C#. Cel mai important pentru noi în acest moment este să avem acces la browser și să îl manipulăm. Pentru proiectul de față sau folosit doar două drivere care permit acest acces Firefox care vine implicit odată cu instalarea Selenium și Google Chrome.

public bool CreateChromeDriver(bool withuseragent,strâng useragentstring, bool noCookies = false)

Exemplul de mai sus conține semnătura driverului de Google Chrome care are trei parametri. Primul de tip bool withuseragent indică utilizarea sau nu a diferiți useri agenți care imită caracteristici specifice anumitor browsere și versiuni de browsere cum ar fi de exemplu cele de mobile. Al doilea parametru repezintă însuși stringul de user agent care vrem să îl folosim la instanțierea driverului. Ultimul parametru indicaă dacă browserul permite sau nu folosirea de cookies.

Tot în această clasă găsim definite și metodele pentru a localiza elemente din DOM și a le returna sau a executa acțiuni asupra acestora. Principale tipuri de moduri de localizare pot fi observate în enumerarea de mai jos.

public enum IdentifyByEnum { Id, LinkText, ClassName, CssSelector, PartialLinkText, XPath, Name, TagName};

În secvența de mai jos putem observa cum folosim enumerarea pentru a crea metodele corespondente Selenium în C#.

public string GetTextValueFromElement(IdentifyByEnum searchBy, string searchElement, string text)

{

return FindElementIntern(searchBy, searchElement).Text.Trim();

}

public bool IsSelectedCheckBox(IdentifyByEnum searchBy, string searchElement)

{

return FindElementIntern(searchBy, searchElement).Selected;

}

Pentru a controla tipul de element folosit avem nevoie de un switch:

switch (searchBy)

{

case IdentifyByEnum.Name:

{

return webDriver.FindElement(By.Name(searchElement));

}

case IdentifyByEnum.Id:

{

return webDriver.FindElement(By.Id(searchElement));

}

case IdentifyByEnum.LinkText:

{

Tot aici avem implemetat și implicit wait care după cum spuneam și în partea teoretică verifică odată la 500 de milisecunde dacă elemental căutat este în pagina.În cazul în care elementul este găsit mai repede decât timpul selectat pentru a aștepta execuția continua reducându-se timpi de așteptare comparativ cu un Thread.Sleep() care așteaptă un anumit timp fix indiferent de ceea ce se întâmplă în DOM.

public void SetImplicitwait(int Seconds)

{

int Minutes = Seconds / 60;

Seconds = Seconds % 60;

TimeSpan time = new TimeSpan(0,Minutes,Seconds);

webDriver.Manage().Timeouts().ImplicitlyWait(time);

}

Un alt fișier comun important este ScreenCapture.cs care poate face la orice moment instantanee ale monitorului pentru a putea aprecia mai bine zona în care avem o defecțiune sau pentru a vedea în mod direct fără a face un debug în prealabil dacă testul nostru nu a fost cu success trecut din cauza unor probleme ale interfeței utilizator sau url-ul accesat este greșit etc.Captura vine ca un mijloc suplimentar de a facilita găsirea cât mai rapidă a problemei.

strâng path = AppDomain.CurrentDomain.BaseDirectory + "\\ScreenCapture";

Fișierul cu capturile ecranului se afla în directorul degbug. Forma pe care o are numele imaginilor este următoarea:

string snapTime=DateTime.Now.ToString("_dd.MM.yyyy-HH.mm.ss");

bitmap.Save(path + "\\" + filename + snapTime + ".png", ImageFormat.Png);

și este formată din numele dat de noi plus dată și ora curentă. Compresia este de tip Png.

Toate aceste metode de folosință comună implementate în aceste clase sunt folosite mai departe de către paginile specifice fiecărei zone din aplicație.Să luăm exemplul casino avem următoarea metoda:

public void PushSpinBtn_ER()

{

seleniumWrapper.WaitButtonAndClick(IdentifyByEnum.XPath, Spin_ER, 120);

}

Avem o metodă nouă pe care să o definim în casino.cs dar pentru a o implementa ne folosim de unele metode implementate în SeleniumWrapper.cs celei de sus corespunzându-i:

public string GetXPathValue(IdentifyByEnum searchBy, string path)

{

return FindElementIntern(searchBy, path).Text;

}

pentru a identifica elementul și metoda următoare pentru a executa acțiunea de așteaptă și click WaitButtonAndClick:

public void WaitButtonAndClick(IdentifyByEnum searchBy, string searchElement,int Seconds)

{

int counter = 0;

bool searchresultisdisplayed = false;

do

{

Thread.Sleep(1000);

counter++;

try

{

searchresultisdisplayed = FindElementIntern(searchBy, searchElement).Displayed;

}

catch

{

searchresultisdisplayed = false;

}

}

while (searchresultisdisplayed == false && counter < Seconds);

if (searchresultisdisplayed == true)

{

Click(searchBy,searchElement);

return;

}

Pentru a scrie în fișierul text și mai apoi pentru a afișa informațiile în foma după cum aminteam folosim log4net.Metoda definită pentru a ne ajuta să creem logarea este următoarea:

public static log4net.ILog log

{

get

{

var a = log4net.LogManager.GetLogger

(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

var file = log4net.LogManager.GetLoggerRepository().GetAppenders().OfType<RollingFileAppender>().FirstOrDefault(fa => fa.Name == "RollingFileAppender");

if (file != null)

{

StackTrace st = new StackTrace();

StackFrame sf = st.GetFrame(1);

file.File = Path.Combine(Environment.CurrentDirectory + @"\logs\" + sf.GetMethod().Name + @".txt");

file.ActivateOptions();

}

return a;

}

}

3.4 Proiectul Services

Acest proiect are ca rol centralizarea tuturor webservice-urilor folosit într-un singur loc pentru a putea controla mai bine ce se întâmplă în proiect.În această zonă putem găzdui web servici cum ar fi un serviciu de content management care să conțină toate textle aferente unui site sau servicii de creare automată de useri sau diferite alte facilități. Este bine să separăm aceste servicii de în soluție pentru a avea un mai mare control și o viziune mai bună asupra lucrurilor.

3.5 Proiectul TestCases

Ultimul proiect din Soluția noastră este TestCases.Acesta ne dă posibilitatea de a scrie teste automate pentru a fi rulate. Pe lângă o structură arborescentă cu testcase-urile avem și aici o serie de clase comune care vin în ajutorul nostrum pentru a crea diferite teste automate.Clasa principală de la care se moștenește este BaseTestCases.cs. Aceasta conține o serie de propietăți.

public class StartInformations: IStart

{

public string applicationStartupPath { get; set; }

public List<string> environments { get; set; }

public List<string> labels { get; set; }

public List<string> languages { get; set; }

public string username { get; set; }

public string password { get; set; }

folosite în special pentru a găsi mediul în care va rula aplicația, aplicația ce o vom rula și nu în ultimul rând limbă pe care rulează aplicația.

Tot de aici se face și call-ul spre pagina principală:

public BaseTestcase(params object[] Params_List) // main page call

{

object Startinfo2 = Params_List[0];

StartInformations Startinfo = (StartInformations)Startinfo2;

environments = Startinfo.environments;

labels = Startinfo.labels;

languages = Startinfo.languages;

sel_sup = new SeleniumWrapper(Startinfo.applicationStartupPath);

username = Startinfo.username;

password = Startinfo.password;

}

In aceasta zonă comună in clasa MobileTestCases.cs avem declarant si atributul cu care marcam metodele pentru a fi indexate in interfata :

[AttributeUsageAttribute(AttributeTargets.Method)]

public class MobileTestCase : Attribute

{

}

}

În continuare vom lua un test și vom vedea toți pasi implicați de la crearea testului până la rularea acestuia și diferitele părți din soluție pe care le folosim la rulare.

Fiecare test case reprezintă o clasă așa că vom începe prin crearea unei clase în proiectul TestCases.Nume clasei este GamePlayCheckBJ_ER iar scopul acestui test este de a testa două jocuri de casino dacă aceste funcționează.Vom verifica dacă acestea sunt accesibile și dacă în momentul în care ne jucăm balanța noastră se updatează. Acest test poate foarte bine să reprezinte un smoke test sau să fie parte a suitei de regression. Pentru o localizare ușoară acesta este creat în folderul casino din proiect.După cum aminteam în proiectul cu interfață stuctura din proiectul acesta este transformată în structura arborescentă de pe interfață.

Constructorul clasei noastre este următorul:

public GamePlayCheckBJ_ER(params object[] Params_List)

: base(Params_List)

{

}

Acesta are un parametru și moștenește clasa base care se afla în proiectul Framework permițând accesul la metodele create în framework pentru manipulare a browserului cu ajutorul librăriilor Selenium.

Următoarea metodă din clasa reprezintă însuși testcase-ul nostru care este de tip bool:

[MobileTestCase]

public bool CasinoPage_GamePlayCheckBJ_ER()

{

//tc

}

După cum se poate observa metoda este decorată cu atributul [MobileTestCases] pentru a face vizibil testul pe interfață.Încă un lucru care este făcut de acest atribut este eliminarea scrierii redundanțe a unei secvențe de foreach care să parcurgă fiecare element din UI cum ar fi testele selectate , limba, mediul de rulare, aplicația asemeni celui de mai jos

foreach (string env in environments)

{

foreach (string label in labels)

{

foreach (string language in languages)

{

Urmează scrierea efectivă a testului.Pentru început trebuie să deschidem driverul. Folosim un driver de chrome cu user agent de Iphone pentru că site-ul aflat sub test este un site mobile și are ca compatibilitate doar versiuni de Iphone și Android.

OpenChrome(true, "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5");

Pe urmă avem nevoie să navigăm spre login .Pentru a naviga avem nevoie de o instanță a clasei lobby din framework și de accesare a metodei GoToURL.Care e formată din protocol , siteul current (CurrentLabel) , limbacurenta (CurrentLanguage) și calea spre pagina dorită.

Lobby lobby = new Lobby(sel_sup, Strings.https + labels, CurrentLanguage);

lobby.GoToURL(Strings.https + CurrentLabel + "/" + CurrentLanguage + "/casino");

Apoi declarăm o variabilă pe care o vom folosi să manipulăm URL-ul unde ne aflăm. Avem nevoie și de o instanță a clasei Header pentru a accesa pagina de login.

var URL = URLFormat.CreateURL(CurrentEnvironemnt, CurrentLabel);

Header header = new Header(sel_sup, URL, CurrentLanguage);

header.PushLoginButton();

Odată ajunși pe pagina de login avem nevoie de un user și de o parolă. Pentru acces la ele vom crea o instantă a clasei CreateUsersConfiguration .

CreateUsersConfiguration usertool = new CreateUsersConfiguration();

Account account = usertool.GetAccount(CurrentLabel, CurrentEnvironemnt);

Login login = new Login(sel_sup, URL, CurrentLanguage);

login.LoginToPage(account.Username, account.Password);

După ce userul este logat instantiem clasa Casino pentru a avea acces la metodele ce manipulează cele două jocuri. Pentru a putea rula testul mai avem nevoie de o metodă de ajutor GameRunCheck care o vom apela din actuala metoda.

Casino casino = new Casino(sel_sup, URL, CurrentLanguage);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_BJ);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_ER);

Metoda de ajutor este următoarea:

protected bool GameRunCheck(Casino casino, string URL, string language, string GameName)

{

bool IsOK=true ;

bool result;

string initialBalance;

string afterBalance;

și aceasta conține patru parametri o instantă de casino, URL-ul , limba și numele jocului aflat sub test. Avem și 4 variabile: un bool IsOk care contorizează starea metodei true dacă putem executa metodele și nu avem exceptii fals în rest.Variabilă result este un Boolean care este true dacă variabilă initialBalance este diferită de afterBalance.

Pentru a aștepta până un anumit element este încărcat în pagina folosim implicit wait.

casino.ImplicitWait(6);

Avem două cazuri: un caz pentru “Play For Fun” în care jocul se desfășoară fără bani reali și un caz pentru “Play For Real” în care jocul se desfășoară cu bani reali.Pentru a diferenția un joc de celelalt if (GameName == Strings.Gamename_BJ) folosim un if else în care comparăm numele jocului cu o constantă definite de noi. Dacă jocul este Black Jack vom mege pe o ramură iar dacă jocul este Roulette vom merge pe cealaltă ramură. Structuraeste următoarea:

if (GameName == Strings.Gamename_BJ)

{

//comenzi pentru jocul Black Jack

}

}

else

{

// comenzi pentru jocul Roulette.

}

Aceeași structură este prezentă și pentru “Play For Fun” doar comenzile diferă puțin întrucât se schimbă ID-urie butoanelor.

Pentru că vorbeam de DSL în partea teoretică a lucrării o oarecare idee a acestei structuri începe să se structureze și în cazul acestui testcase bineînțeles la un nivel incipient dar o asemănare există.

casino.PushPlayButtonForGame(GameName); casino.PushPlayButtonInGame(GameName, true);

initialBalance = casino.ReturnBalance();

casino.PushPlaceBetTable_ER();

casino.PushSpinBtn_ER()

Dacă ne uităm atent la instrucțiunile de mai sus vom observa faptul că textul este destul de intuitiv și pentru o persoană care vede pentru prima dată bucata de cod sau chiar și pentru o persoană fără cunoștințe de programare.Putem chiar scrie sub forma textuală instrucțiunile de mai sus:” Apasă butonul joacă pentru joc după care apasă butonul joacă din joc returnează balanță și salvează-o în variabilă balanța inițială apasă butonul pune pariu pe masă și apasă butonul învârte”. Chiar dacă în teorie este ideal să nu avem instante ale unor clase în teste în acest caz particular instanta clasei ne spune domeniul din aplicație în care ne aflăm sau zona respectiv casino.

Iar pentru a ne asigura că jocul functionază comparăm balanta inainte de a juca o rundă și după ce am jucat runda. Dacă acestea sunt diferite atunci jocul funcționează.Codul pentru aceasta comparație este următorul.

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("ER_PFF not working on: " +CurrentLabel+ CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("ER_PFF_noWork");

IsOK = false;

}

În cazul în care variabila result este falsă adică balanțele nu sunt identice variabila noastra IsOK este “true” adică jocurile funcționează. În caz contrar vom loga faptul că balanța este identică vom face o captură a ecranului și vom seta variabila bool IsOK falsă.

Intreaga structură atât a metodei ajutătoare cât și a metodei principale este inclusă într-un try –catch.

[MobileTestCase]

public bool CasinoPage_GamePlayCheckSlots()

{

try

{// instructiuni}

catch (Exception e)

{

Logging.log.Error(e.ToString());

return false;

}

finally

{

CloseBrowser();

}

return true;

În cazul în care apar apar excepții în timpul rulării cum ar fi de exemplu elemente care nu sunt identificate sau poate structura păgânilor s-a schimbat sau elemente din framework nu funcționează cum ne-am aștepta acestea sunt prinse de către structura catch și logate pentru a putea face debug. Fie că se găsește o excepție fie că nu se execută și structura finally care închide browserul și implicit driverul folosit.

În cazul în care testul se execută cu succes este returnată valoarea de adevăr “true” care raportează pe interfața pe un fond verde success fie în cazul în care testul întâmpina excepții sau condiția nu a fost îndeplinită va intra în structura catch și va retrurna fals în cazul excepților fie va returna tot fals dacă condiția de test nu este îndeplinită.

Fig .3.7 Executare TestCase

În diagrama de mai sus este o scurtă prezentare a zonelor parcurse la executarea testului. După începerea rulări testul își ia informațiile necesare despre mediul de test, aplicație și limba din interfață. Ulterior se folosesc din framework diferite zone cum ar fi casino unde avem definite metode ce pot acționa zone specifice casino-ului din aplicația noastră sau zona lobby folosită pentru navigarea până la pagina de login și nu în ultimul rând cea shared unde se află Selenium core. Zona framework comunică în mod permanent cu testul nostru cu fiecare linie executată din test case până în momentul în care are loc raportarea care se face tot în interfață.

Un alt test care este implementat verifică prezența Google Tag Manager în pagină.

În cazul în care nu putem să identificăm un obiect sau este nevoie de o execuție a unui script pentru acces putem folosi una din metodele Selenium pentru executare a scripturilor.

În cazul nostru în unul din test case-uri încercam să vedem dacă Google Tag Manager este prezent în pagina.Acesta arată în felul următor:

3.6 Registration test case

Unul din testele automate clasice care este valabil pentru majoritatea aplicațiilor web ce necesită crearea unui cont de utilizator este înregistrarea (registration). În cazul nostru formularul pentru înregistrare conține doi pași respectiv două pagini ce trebuie submise.Validarea pe server se face la ultimul pas, pagina numărul doi. Folosim două metode separate pentru a completa fiecare pagină în parte prin intermediul unei instante a clasei Registration.

reg.FillFirstRegPage();

reg.Submit

reg.FillSecondRegPage();

Codul pe care aceste metode îl cheamă este de forma următoare:

m_wrapper.Clear(IdentifyByEnum.Id, "Input_LastName");

m_wrapper.SendKeys(IdentifyByEnum.Id, "Input_LastName", m_regData.LastName);

m_wrapper.SendKeys(IdentifyByEnum.Id, "Input_DateOfBirth_Day", m_regData.Day);

m_wrapper.SetDropDownValue("Input_DateOfBirth_Month", m_regData.Month);

m_wrapper.SendKeys(IdentifyByEnum.Id, "Input_DateOfBirth_Year", m_regData.Year);

Se trimit valori în spre interfața cum ar fi: nume, prenume, adresa, data nașterii etc. Aceste date sunt creeate cu ajutorul clasei RegistrationData. În această clasă avem o serie de proprietăți autoimplementate care ne ajută la completarea formularului de înscriere.

public string FirstName { get; set; }

public string LastName { get; set; }

public string SecondLastName { get; set; }

Majoritatea câmpurilor sunt hardcodate însă pentru numele de identificare al utilizatorului sau pentru email avem nevoie de date unice de identificare. Pentu a depăși această problemă folosim fie folosim o instantă a clasei Random aflată în librăria C# fie încercam să compunem cu ajutorul orei și datei actuale intrări unice. Putem observa în cazul generării numărului de telefon folosirea clasei Random iar pentu email folosirea DateTime. Pentru a ne putea genera datele aleatorii invocăm clasa RegistrationData regData = new RegistrationData().

private void SetRandomData()

{

Random rand = new Random();

FirstName = "FirstName";

LastName = "LastName";

SecondLastName = "SecondLastName";

PhoneNumber = "7" + rand.Next(99999999);

Email = DateTime.Now.Year + DateTime.Now.Month.ToString() + DateTime.Now.Day + DateTime.Now.Hour+DateTime.Now.Minute + DateTime.Now.Second + DateTime.Now.Millisecond + "[anonimizat]";

folosim clasa de bază moștenită din Testcase helper care ne ajută să pornim driverul.

Ajungem în framework, Selenium_Wrapper zona unde sunt definite driverele atât pentru Chrome cât și pentru Firefox. Aici sunt evaluate elemente cum ar fi dacă avem user agent , cookies etc.

Putem să folosim și un wait pentru a aștepta până browserul se încarcă după care revnim în metoda din Base.Testcase și implicit înapoi în test cu driverul inițializat.Mai departe putem accesa URL-ul dorit.

3.7.2 Debug pentru click pe element

Traseul pe care îl are în soluția noastră identificarea și acțiunea de click pe un element din pagina este următoarea:

Ajungem în zona în care sunt definite metodele pentru pagina de casino unde apelăm metoda PushPlayButtonForGame care la rândul său apleaza două metode definite în Selenium_Wrapper. Una este metoda de click iar cealaltă este de căutare a elementului pe care vrem să apăsăm.

Căutam elementul din pagină în funcție de elementul de căutare (gen id, clasa…) și revenim în rularea următoarei linii de cod din test.

3.7.3 Debug pentru raportare( logging)

Partea de afișare a rezultatelor în interfața grafică are următorul traseu în soluție:

Se încearcă scrierea log-urilor în fișierul text care este creat dacă nu există acesta rămâne deschis pentru a se putea scrie în el dar și pentru a citi din el.

Informațiile sunt citite din fișierul text și afișate în patea de raportare interfeței utilizator

și afișate. Afișarea este sub formă de HTML cu formatul specificat în amintită în prezentarea interfeței.

După ce informațiile sunt scrise în fișier acesta este închis.

IV. CONCLUZII

4.1 Beneficii aduse de automatizare

Automatizarea aduce mari beneficii procesului de testare și implicit calității unui produs software. Pe lângă siguranța pe care o oferă automatizarea asigură și o testare bună a întregului sistem, aceasta reduce munca redundantă adesea obositoare din punct de vedere psihic pentru testeri întrucât aceștia trebuie să repete la un timp foarte scurt aceleași test case-uri. De multe ori această repetare a unor procese/teste manual duce la erori din cauza neglijenței dată de monotonie.

De asemenea dacă nu există o planificare și o expertiză foarte bună, dacă automatizarea ar aduce intradevar beneficii acesta este susceptibilă eșecului. Factorii principali care ar duce la un eșec sunt: nepregătirea suficientă a personalului pentru a înțelege procesele de automatizare, raportul timpului necesar automatizării / cost, alegerea tool-ului care să se preteze la nevoile proiectului, ușurința cu care se poate folosi framework-ului de automation. În special proiectele mari care se întind pe mai multe iterații vor avea un real avantaj în implementarea unor teste automate.

Revenind la aplicația noastră framework-ul poate fi portat și adaptat pentru orice tip de aplicație fie ea desktop sau mobile de tip web. Fapul că suportă o gamă largă de browsere și poate face diferite acțiuni ce țin de opțiuni cum ar fi activare și dezactivare de cookies, javascript, adăugare de user agent fac ca framework-ul să fie versatil. Alegerea Selenium Webdriver împreună cu C# este o alegre bună întrucât supportul de care beneficiază ambele este foarte bun atât pe site-urile oficiale cât și pe site-urile adiacente. De asemenea în cazul în care framework-ul este dezvoltat de testare într-un limbaj popular cum ar fi C# sau Java aceștia pot beneficia la nevoie de suport din partea development-ului.Faptul că framework-ul poate fi costumizat pentru orice aplicație web aduce un plus de velocitate în crearea de teste automate.

4.2 Îmbunătățiri ce pot fi aduse

Ca o îmbunătățire față de actualul stadiu partea de logare a testelor ar putea suferi modificări pentru o mai bună logare a pașilor și un acces mai bun la informații. Interfața poate fi îmbunătățită ca funcționalitate și design. Putem integra Selenium Server pentru a putea rula testele în grid adică în paralel și nu secvențial ca în momentul de față.

Poate cel mai important factor al framework-ului este că acesta folosește Selenium care este un tool open source gratis extrem de versatil.

Dacă vrem să ne orientăm spre testarea aplicațiilor native sau hibrire (aplicații web care sunt împachetate într-o aplicație ) fie pentru sistemele de operare Android fie pentru IOS putem folosi Appium care este și acesta un tool open source care folosește același protocol JSON wire protocol folosit și de Selenium Webdriver.

Un alt avantaj pe care îl aduce folosirea Appium este faptul că testele pot fi rulate

direct pe device (aparat) prin intermediul conectării la un cablu USB nefiind necesară

instrumentarea aparatului pe care se rulează testul. Pentru că instrumentarea reprezintă

injectarea unui javascript pentru a putea rula testele iar injectarea acestuia poate duce la modificări de comportament ale aparatului aflat sub test folosirea Appium crește gradul de încredere al testelor. De asemenea testele pot fi rulate și pe simulatoare.

V. BIBLIOGRAFIE

[1] Beginning Visual C# 2012 Programming, Karli Watson, Jacob Vibe Hammer, Jon Reid, Morgan Skinner, Daniel Kemper, Christian Nagel

[2] Selenium 2 Testing Tools 2012 , David Burns

[3] Suport de curs Programare Avansata , Honoriu Valean

[4] http://docs.seleniumhq.org/docs/03_webdriver.jsp

[5] http://msdn.microsoft.com/en-us/library/67ef8sbd.aspx

[6] http://www.pluralsight.com/training Selenium Tutorials

VI. ANEXE

Anexa1- Exemplu de Testcase

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using Framework.Portal;

using Framework.Shared;

using Testcases.TestCasesHelper;

using Framework.Casino;

using Framework.UserCreate;

using Framework.UserCreate.Models;

namespace Testcases._02_Casino

{

class GamePlayCheckBJ_ER : BaseTestcase

{

public GamePlayCheckBJ_ER(params object[] Params_List)

: base(Params_List)

{

}

[MobileTestCase]

public bool CasinoPage_GamePlayCheckBJ_ER()

{

try

{

OpenChrome(true, "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5");

Lobby lobby = new Lobby(sel_sup, Strings.https + labels, CurrentLanguage);

lobby.GoToURL(Strings.https + CurrentLabel + "/" + CurrentLanguage + "/casino");

// lobby.GoToURL(Strings.http + CurrentEnvironemnt + "." + CurrentLabel + "/" + CurrentLanguage + "/casino");

// var URL = "Strings.http" + CurrentEnvironemnt + "." + CurrentLabel;

var URL = URLFormat.CreateURL(CurrentEnvironemnt, CurrentLabel);

Header header = new Header(sel_sup, URL, CurrentLanguage);

header.PushLoginButton();

CreateUsersConfiguration usertool = new CreateUsersConfiguration();

Account account = usertool.GetAccount(CurrentLabel, CurrentEnvironemnt);

Login login = new Login(sel_sup, URL, CurrentLanguage);

login.LoginToPage(account.Username, account.Password);

Casino casino = new Casino(sel_sup, URL, CurrentLanguage);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_BJ);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_ER);

}

catch (Exception e)

{

Logging.log.Error(e.ToString());

return false;

}

finally

{

CloseBrowser();

}

return true;

}

protected bool GameRunCheck(Casino casino, string URL, string language, string GameName)

{

bool IsOK=true ;

bool result;

string initialBalance;

string afterBalance;

try

{

// Play for Real starts here

if (GameName == Strings.Gamename_BJ)

{

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, true);

initialBalance = casino.ReturnBalance();

casino.PushPlaceHand1_BJ();

casino.PushDealBtn_BJ();

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushStandBtn_BJ();

afterBalance = casino.ReturnBalance();

Thread.Sleep(3000);

casino.ImplicitWait(3);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("BJ_PFR button not working on" + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("BJ_PFR_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

else

{

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, true);

initialBalance = casino.ReturnBalance();

casino.PushPlaceBetTable_ER();

casino.PushSpinBtn_ER();

Thread.Sleep(6000);

casino.ImplicitWait(6);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info(" ER_PFR not working on" + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("ER_PFR_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

// Play for Fun starts here

if (GameName == Strings.Gamename_BJ)

{

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, false);

initialBalance = casino.ReturnBalance();

casino.PushPlaceHand1_BJ();

casino.PushDealBtn_BJ();

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushStandBtn_BJ();

afterBalance = casino.ReturnBalance();

Thread.Sleep(3000);

casino.ImplicitWait(3);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("BJ_PFF not working on: " + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("BJ_PFF_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

else

{

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, false);

initialBalance = casino.ReturnBalance();

casino.PushPlaceBetTable_ER();

casino.PushSpinBtn_ER();

Thread.Sleep(6000);

casino.ImplicitWait(6);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("ER_PFF not working on: " +CurrentLabel+ CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("ER_PFF_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

}

catch (Exception e)

{

Logging.log.Info("Error in HELP method"+GameName);

Logging.log.Error(e.ToString());

ScreenCapture.MakeScreenShot("CasinoGameplayBJ_ER_ErrorHelpMet");

CloseBrowser();

return false;

}

return IsOK ;

}

}

}

BIBLIOGRAFIE

[1] Beginning Visual C# 2012 Programming, Karli Watson, Jacob Vibe Hammer, Jon Reid, Morgan Skinner, Daniel Kemper, Christian Nagel

[2] Selenium 2 Testing Tools 2012 , David Burns

[3] Suport de curs Programare Avansata , Honoriu Valean

[4] http://docs.seleniumhq.org/docs/03_webdriver.jsp

[5] http://msdn.microsoft.com/en-us/library/67ef8sbd.aspx

[6] http://www.pluralsight.com/training Selenium Tutorials

ANEXE

Anexa1- Exemplu de Testcase

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using Framework.Portal;

using Framework.Shared;

using Testcases.TestCasesHelper;

using Framework.Casino;

using Framework.UserCreate;

using Framework.UserCreate.Models;

namespace Testcases._02_Casino

{

class GamePlayCheckBJ_ER : BaseTestcase

{

public GamePlayCheckBJ_ER(params object[] Params_List)

: base(Params_List)

{

}

[MobileTestCase]

public bool CasinoPage_GamePlayCheckBJ_ER()

{

try

{

OpenChrome(true, "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5");

Lobby lobby = new Lobby(sel_sup, Strings.https + labels, CurrentLanguage);

lobby.GoToURL(Strings.https + CurrentLabel + "/" + CurrentLanguage + "/casino");

// lobby.GoToURL(Strings.http + CurrentEnvironemnt + "." + CurrentLabel + "/" + CurrentLanguage + "/casino");

// var URL = "Strings.http" + CurrentEnvironemnt + "." + CurrentLabel;

var URL = URLFormat.CreateURL(CurrentEnvironemnt, CurrentLabel);

Header header = new Header(sel_sup, URL, CurrentLanguage);

header.PushLoginButton();

CreateUsersConfiguration usertool = new CreateUsersConfiguration();

Account account = usertool.GetAccount(CurrentLabel, CurrentEnvironemnt);

Login login = new Login(sel_sup, URL, CurrentLanguage);

login.LoginToPage(account.Username, account.Password);

Casino casino = new Casino(sel_sup, URL, CurrentLanguage);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_BJ);

GameRunCheck(casino, URL, CurrentLanguage, Strings.Gamename_ER);

}

catch (Exception e)

{

Logging.log.Error(e.ToString());

return false;

}

finally

{

CloseBrowser();

}

return true;

}

protected bool GameRunCheck(Casino casino, string URL, string language, string GameName)

{

bool IsOK=true ;

bool result;

string initialBalance;

string afterBalance;

try

{

// Play for Real starts here

if (GameName == Strings.Gamename_BJ)

{

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, true);

initialBalance = casino.ReturnBalance();

casino.PushPlaceHand1_BJ();

casino.PushDealBtn_BJ();

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushStandBtn_BJ();

afterBalance = casino.ReturnBalance();

Thread.Sleep(3000);

casino.ImplicitWait(3);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("BJ_PFR button not working on" + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("BJ_PFR_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

else

{

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, true);

initialBalance = casino.ReturnBalance();

casino.PushPlaceBetTable_ER();

casino.PushSpinBtn_ER();

Thread.Sleep(6000);

casino.ImplicitWait(6);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info(" ER_PFR not working on" + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("ER_PFR_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

// Play for Fun starts here

if (GameName == Strings.Gamename_BJ)

{

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, false);

initialBalance = casino.ReturnBalance();

casino.PushPlaceHand1_BJ();

casino.PushDealBtn_BJ();

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushStandBtn_BJ();

afterBalance = casino.ReturnBalance();

Thread.Sleep(3000);

casino.ImplicitWait(3);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("BJ_PFF not working on: " + CurrentLabel + CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("BJ_PFF_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

else

{

Thread.Sleep(6000);

casino.ImplicitWait(6);

casino.PushPlayButtonForGame(GameName);

casino.PushPlayButtonInGame(GameName, false);

initialBalance = casino.ReturnBalance();

casino.PushPlaceBetTable_ER();

casino.PushSpinBtn_ER();

Thread.Sleep(6000);

casino.ImplicitWait(6);

afterBalance = casino.ReturnBalance();

result = initialBalance.Equals(afterBalance, StringComparison.Ordinal);

if (result == false)

{

IsOK = true;

}

else

{

Logging.log.Info("ER_PFF not working on: " +CurrentLabel+ CurrentEnvironemnt + CurrentLanguage + GameName);

ScreenCapture.MakeScreenShot("ER_PFF_noWork");

IsOK = false;

}

casino.PushHomeButtonInGame(GameName);

casino.PushHomeButtonInGameLobby();

}

}

catch (Exception e)

{

Logging.log.Info("Error in HELP method"+GameName);

Logging.log.Error(e.ToString());

ScreenCapture.MakeScreenShot("CasinoGameplayBJ_ER_ErrorHelpMet");

CloseBrowser();

return false;

}

return IsOK ;

}

}

}

Similar Posts

  • Serviciu Web de Agregare Automata a Informatiilor

    Cuprins 1. Introducere 1.1 Motivația alegerii temei Trăim în era informației. În prezent majoritatea informațiilor sunt prezentate și transmise doar în forma digitală. Cantitatea informației noi generate zilnic este enormă și este în continuă creștere. Valoarea informațiilor noi poate să fie foarte imporantă și accesul rapid la aceste informații poate să constituie o necesitate imediată….

  • Numere Naturale

    Numere naturale. Operați cu numere naturale Repere din istoria matematicii Precizăm, încă de la început, că matematica este universală și atotprezentă. Cultura și matematica s-au dezvoltat împreună de-a lungul vremii. Numerele sunt notate prin simboluri, dar culturi diferite ale omenirii au utilizat pentru ele simboluri diferite. Cuvântul calcul provine din cuvântul latin ,, calculus”- pietricică….

  • Teoria Comertului International

    TEORIA COMERȚULUI INTERNAȚIONAL CUPRINS Cap.1 TEORIA CLASICĂ A COMERȚULUI INTERNAȚIONAL 1.1 Delimitarea obiectului de analiză al teoriei comerțului internațional 1.2 Precursorii și fondatorii teoriei comerțului internațional 1.3 Teoria avantajelor absolute – Adam Smith 1.4 Teoria costurilor comparative 1.5 Costurile absolute comparate 1.6 Costurile relative comparate 1.7 Semnificația teoriei costurilor relative și a avantajului comparativ 1.8…

  • Analiza Unui Grup de Discutii pe Internet

    Cuprins 1. Introducere………………………………………………………………………………………………….1 2. Arhitectura aplicatiei…………………………………………………………………………………….2 3. Implementare………………………………………………………………………………………………6 3.1 Alegerea limbajului…………………………………………………………………………………….6 3.2 Caracteristici care au impus alegerea limbajului…………………………………………….7 3.3 Alegerea mediului de dezvoltare………………………………………………………………..10 3.3.1 Sockets…………………………………………………………………………………………………10 3.3.2 Datagrame…………………………………………………………………………………………….12 3.3.3 RMI……………………………………………………………………………………………………..13 3.3.3.1 Asemanari intre modelul obiectelor distribuite si cel al obiectelor locale……………………………………………………………………………………………………………15 3.3.3.2 Deosebiri intre modelul obiectelor distribuite si cel al obiectelor locale……………………………………………………………………………………………………………15 3.3.3.3 Activarea obiectelor la…