Bug - O problemă, eroare, defect, posibilitate nedocumentată, greșeală într-un sistem software care împiedică sistemul să funcționeze așa cum este de așteptat este un bug.
Bug report - Un raport care detaliază un bug într-un program, adică cum se manifestă, când, care parte a codului este responsabilă, eventual și o soluție posibilă.
Bug tracking - Bug tracking-ul este un mod organizat de a ține evidența bugurilor și a stărilor acestora (deschis, rezolvat, testat, închis). Acesta poate varia de la forme neorganizate (întâlniri în echipă) la forme organizate (liste de discuții, mail-uri, soluții specializate).
Sistem de bug tracking - O aplicație software care are ca rol ușurarea bug tracking-ului (este o metodă eficientă centralizată și ușor utilizabilă.) Există soluții gratuite, dar și soluții enterprise cu prețuri foarte ridicate. Un sistem de bug tracking este un subtip de sistem de issue tracking.
Sistem de issue tracking - O aplicație software care are ca rol centralizarea și adresarea tuturor cererilor legate de unul sau mai multe produse, de la probleme la schimbări de design și aplicări de patch-uri. Cele mai multe sunt în același timp și bug trackere. În general, sunt mai complexe decât bug trackerele.
Patch - O mică bucată de software creată spre a rezolva problemele și a îmbunătăți performanțele unui program. Aceasta include, dar nu este limitata la: repararea de bug-uri, creșterea vitezei, îmbunătățirea graficii. Unele patch-uri creează și probleme noi.
Patch management - Procesul de a stabili o strategie și a plănui ce patch-uri să fie aplicate, la ce sisteme și când este momentul potrivit pentru aplicarea lor.
Așa cum a fost descris în cadrul laboratorului 4, GitHub permite și un management al bug-urilor.
Redmine este un tool complex, care oferă și suport pentru bug tracking. Prin secțiunea “New issue” se pot publica bug-uri, iar aceastea pot fi urmărite.
Bugzilla este unul dintre cele mai populare sisteme de urmărire a bug-urilor având o multitudine de functionalitati.
Trac nu este atât de sofisticat ca Bugzilla în ce privește urmărirea bugurilor (adică bug tracking), dar oferă mult mai multe alte facilități precum un navigator de Subversion și un wiki, deci o platformă completă de colaborare între utilizatori și dezvoltatori. De asemenea Trac poate fi extins ușor prin intermediul modulelor, unul dintre cele mai populare fiind cel pentru code review.
Fiecare bug are o adresă de mail distinctă. Comentariile și controlul bug-urilor se face cu emailuri tipizate.
Launchpad este o aplicație web și un site pentru publicarea proiectelor software (în special cele open source). Printre multe alte facilități interesante dispune și de bug-tracking.
Launchpad poate centraliza rapoartele bugurile din mai multe surse independente și oferă posibilitatea dezvoltatorilor de a discuta despre acel bug într-un singur loc. Launchpad se integrază bine cu trackere externe: Bugzilla, Trac, Sourceforge, Roundup, Mantis, RT și Debian BTS. Launchpad încearcă să elimine patchurile scrise în comentarii prin oferirea posibilității de publicare a unei ramure de cod (branches). Bugurile pot fi urmărite prin email și atom feeds, fiecare bug având asociată o adresa de email (ex: 249177@bugs.launchpad.net).
Un fișier patch e un fișier text care descrie diferențele dintre două versiuni ale unui fișier sau dintre două fișiere distincte. Există două formate standard pentru astfel de fișiere: tipul normal și context copiat. Mai jos este prezentat un format îmbunătățit, Context unificat, care este cel mai întâlnit și mai ușor de vizualizat format.
Structura unui fișier patch cu context unificat:
--- original_file_name comentarii (ștampilă de timp, versiunea fișierului în svn/git/etc., etc.) +++ modified_file_name comentarii (idem) @@ -start_line__original_file,nr_lines__original_file +start_line__modified_file,nr_lines__modified_file @@ context_line_before_1 context_line_before_2 ... context_line_before_n - original_line_1 - original_line_2 ... - original_line_m + modified_line_1 + modified_line_2 ... + modified_line_p context_line_after_1 context_line_after_2 ... context_line_after_n
Exemplu de fișier patch cu context unificat:
--- v1.c 2008-11-18 02:34:38.000000000 +0200 +++ v2.c 2008-11-18 02:38:14.000000000 +0200 @@ -261,8 +261,18 @@ if (build_key(argv[1])) return 2; - display("original message: [%s]\n", msg, blocks); - + //display("original message: [%s]\n", msg, blocks); + if (blocks) + { + char c; + char * fmt = "original message: [%s]\n"; + int len = blocks; + c = msg[len-1]; + if (c == 'X') + msg[len-1] = '\0'; + printf(fmt, msg); + msg[len-1] = c; + } apply(msg, blocks, normalize); encrypt((unsigned short*) msg, blocks/2);
'diff
' e un program cu care se pot crea fișiere de tip patch având la dispoziție fișierul original și fișierul modificat.
diff
poate crea fișiere patch în oricare din cele trei formate standard:
diff origial_filename modified_filename
pentru a crea un fișier patch cu un număr implicit de linii de context unificat
:
diff -u origial_filename modified_filename
pentru a crea un fișier patch cu x linii de context unificat
:
diff -Ux origial_filename modified_filename
git
poate genera fișiere de patch care descriu diferențele între două commit-uri.
Implicit git format-patch
crează un fișier diff în format unificat (cel mai răspândit format în lumea open-source) și îl scrie la stdout. Pentru a-l scrie într-un fișier pe disc, trebuie redirectată ieșirea către un fișier:
git format-patch [optional parameters] > file.patch
Un fișier patch
nu este folosit doar pentru a vizualiza diferențele între două versiuni ale unor fișiere, ci și pentru a transmite un anumit set de modificări de la un utilizator la altul pentru a fi aplicate.
Utilitarul standard cu care se aplică patch-uri se numește patch
.
Modul cel mai întâlnit de utilizare este:
patch -pNUM < filename.patch
patch
își ia fișierul din stdin, de aceea trebuie redirectat fișierul de intrare.
În fișierul filename.patch
, diff
sau git format-patch
va scrie și numele fișierelor pe care le-a comparat și din conținutul cărora a extras diferențele. E posibil ca diff
sau git format-patch
să fie rulate într-un alt director față de cel în care se va rula patch
. Cu opțiunea -pNUM
se specifică numărul de nivele din calea specificată în fișierul filename.patch
care vor fi ignorate când se va încerca să se determine.
De asemenea, un patch poate fi aplicat cu comanda:
git am filename.patch
Pentru o testare de calitate, este important să existe o planificare riguroasă a testării încă din faza de proiectare sau development. Pe măsură ce se conturează definițiile modulelor, entităților de date, obiectelor, claselor, funcțiilor, etc. este recomandabil să se scrie și “scenarii” de testare ale acestora, fie top-down, fie bottom-up.
În industria software, “scenariile” de test se numesc test cases.
Un exemplu de test case:
trebuie verificată funcționarea unei pagini de login care conține un input de user name și unul de parolă
Există “testare pozitivă” și “testare negativă”, concretizată în positive test cases și negative test cases. Testarea pozitiva înseamnă verificarea faptului că sistemul face ceea ce trebuie să facă. Testarea negativă înseamnă verificarea faptului că sistemul nu face ceea ce nu trebuie să facă.
Pe cazul anterior:
În principiu, cele două approachuri sunt echivalente, însă în practică testarea pozitivă se referă la funcționarea “normală” a sistemului, iar testarea negativă la “corner cases”. De exemplu, pentru testarea unui feature critic ca time to market dar non-critic ca și calitate (ex. twitter), se va prefera testarea pozitivă, care asigură că sistemul funcționează corect pentru cei mai mulți utilizatori. Pentru testarea unui feature critic ca și calitate (ex. online banking) se va insista pe teste negative, ex. se va încerca “spargerea” sistemului prin combinații incorecte.
Există, ca în orice alt domeniu, tool-uri open source pentru managementul test cases:
Se aplică în cazul în care pentru programul ce trebuie testat sursele nu sunt disponibile, ci doar interfața de acces (binarul, o interfața implementată de clasa testată, etc). Cum se testează: Se aplică un set de intrări, iar ieșirile sunt comparate cu un set de ieșiri corecte.
Exemplu Testarea unui program care la intrare primește un string pe care vrea să îl parseze în
Boundary testing sau boundary value analysis este o metodă de proiectare a suitelor de teste pentru cazurile în care se folosesc valori la limită acceptate de program. În general, accentuează testarea “corner case”-urilor. Unele teste care fac parte din suita boundary testing sunt “stress tests”.
În general, boundary value analysis se realizează în doi pași: # identificarea claselor de echivalență # proiectarea suitelor de test
Primul pas înseamnă, de obicei, partiționarea valorilor posibile în clase valide și invalide. Exemplu Un program care primește valori pozitive până în 99, va avea trei clase:
Al doilea pas înseamnă proiectarea unei suite de teste care vor selecta anumite valori care să verifice reacția programului la valori valide sau invalide. Exemplu Dacă un program primește valori în domeniul [-999,999], atunci o suită posibilă de test ar fi:
În general, testele trebuie să includă prima și ultima valoare posibilă. De asemenea, se recomandă testarea de condiții extreme de intrare sau ieșire (valori foarte mici, foarte mari, invalide etc.)
Problemele pe care le detectează boundary testing sunt, de obicei:
Unit testing este o metodă folosită pentru a testa fiecare componentă a unui proiect. O unitate este cea mai mică componentă a unei aplicații. În mod ideal modulele de test sunt independente unele de celelalte. Pentru fiecare unitate se fac teste separate.
Există și o abordare Test Driven Development - TDD în care se scrie testul pentru unitate înainte de scrierea codului.
O problemă des întâlnită în testarea proiectelor este testarea unei părți a proiectului înainte ca alte părți să fie gata. Se pot folosi pentru asta interfețe, numite Stubs, care simulează funcțiile de bază ale obiectului respectiv fără să efectueze și teste de integritate a datelor sau ale fluxului logic al problemei. Ele sunt des folosite în cursul dezvoltării unităților proiectului care depind de obiectul simulat. Accentul este pus pe verificarea răspunsului dorit / schimbării de stare.
Mockups sunt tot implementarea unor interfețe care testează mai aprofundat funcțiile necesare. Ele simulează spre exemplu funcționarea unui server pentru a putea testa facilitățile clientului și testează de asemenea autentificarea clientului înainte ca acesta să poată efectua anumite tranzacții. Pentru o utilizare mai facilă se recomandă folosirea interfețelor și utilizarea lor în funcția de testare. O implementare pentru testare este o implementare care conține numai cod de test și imită cât mai bine funcționarea viitorului obiect. Accentul este pus pe verificarea comportamentului. Mockup-urile sunt utile în multe situații precum: * cazul când obiectul în sine nu există * obiectul real/funcția reală ia foarte mult timp să ruleze * obiectul real este prea dificil de pus în funcțiune * funcția reală returnează valori nedeterministe și se dorește testarea comportării cu toate valorile limită * funcția reală necesită interacțiunea cu utilizatorul și nu se poate folosi în teste automate
Important este ca atunci când se folosesc obiecte pentru simulare, trebuie să se țina cont de faptul că obiectul trebuie să simuleze cât mai bine realitatea. Există și facilități implementate pentru folosirea mockup-urilor în .NET precum NMock, POCMock, .NET Mock Object.
“Also as a consequence of the introduction of new bugs, program maintenance requires far more system testing per statement written than any other programming. Theoretically, after each fix one must run the entire batch of test cases previously run against the system, to ensure that it has not been damaged in an obscure way. In practice, such regression testing must indeed approximate this theoretical idea, and it is very costly.” – Fred Brooks, The Mythical Man Month (p 122)
Regression testing implică verificarea ca odată cu avansarea în proiect să nu se piardă funcționalități deja implementate, sau să se genereze erori noi.
Cea mai simplă și eficientă metodă de regression testing este să se păstreze toate testele într-un batch care să se ruleze periodic, astfel orice bug nou va fi remarcat imediat și poate fi remediat. Desigur, asta implică ca testele respective să poată fi rulate automat.
'Fault injection' este o metodă de testare software care implică generarea de input-uri care să ducă programul pe căi (în general de error handling) care altfel ar fi parcurse foarte rar în decursul unei testări normale, îmbunătățind astfel foarte mult code coverage-ul.
Există atât software cât și hardware fault injection.
Există încă din 1970, și implică crearea de scurtcircuite pe placă, generând astfel erori.
Se împarte în două mari categorii # Compile time injection # Run time injection
Modificarea de linii de cod la compilare pentru a genera comportamente eronate. Ex: a++ poate fi modificat în a–;
Există mai multe utilitare pentru testarea automată a programelor cu interfețe grafice (o listă mai detaliată aveți aici).
AutoIt este un limbaj de programare asemănător Visual Basic cu un compilator ce rulează pe Windows și care permite (printre altele):
Scripurile pot fi compilate sub forma unor executabile Win32.
Două tutoriale de AutoIt: interacțiune cu notepad și instalare winzip
Abbot este o platformă de testare automată a aplicațiilor GUI scrise în Java. Testele sunt scrise sub forma unor unit-test-uri. Mai multe detalii pe site-ul proiectului.
Deși folosite în special pentru optimizări și pentru identificarea bottleneck-urilor din sistem, utilitarele de tip code-coverage și code-profiling pot fi folosite pentru detectarea anumitor tipuri de probleme precum bucle infinite, sincronizare ineficientă etc.
Utilitarele de tipul code coverage sunt folosite în procesul de testare a programelor pentru inspectarea unei părți cât mai mari a programului. Diversele tipuri de mecanisme de tip code coverage sunt folosite pentru a determina ce funcții sunt acoperite la o rulare, ce instrucțiuni sunt apelate, ce fluxuri de execuție sunt parcurse.
Programele folosesc opțiuni speciale de code-coverage. Cu ajutorul acestor opțiuni se pot determina funcțiile sau instrucțiunile des (sau rar) folosite și oferă o imagine a nivelului de testare a anumitor părți dintr-un program.
În general, utilitarele de code coverage sunt privite ca utilitare pentru depanare automată și sunt folosite, de obicei, de inginerii de testare. Depanarea efectivă, cu utilitare de debugging specializate, este realizată, în general de dezvoltatorii care au cunoștință de codul inspectat.
Profilerele sunt utilitare care prezintă informații referitoare la execuția unui program. Sunt utilitare care intră în categoria “dynamic analysis” spre deosebire de alte programe care intră în categoria “static analysis”.
Profilerele folosesc diverse tehnici pentru colectarea de informații legate de un program. De obicei se obțin informații de timp petrecut în cadrul unei funcții (nivel ridicat) sau numărul de cache miss-uri, TLB miss-uri (nivel scăzut).
În general, un program care este “profiled” este instrumentat astfel încât, în momentul rulării, să ofere la ieșire informațiile utile dorite. Spre exemplu, pentru a folosi opțiunile gprof, se folosește opțiunea -pg
transmisă gcc.
Cel mai cunoscut model de atribute ale produselor software de calitate este FURPS+ model, care cuprinde următoarele atribute:
Au apărut standarde dedicate produselor software, de tipurile:
Ulterior, s-au definit proceduri:
Activitățile principale SQA sunt:
Activitățile de evaluare și monitorizare au loc în cadrul auditurilor. Auditul este tehnica SQA de bază folosită pentru verificarea calității produsului
Există activități SQA specifice fazelor ciclului de viață al proiectului
În general, scopul unei organizații este crearea unui SQAP care să asigure nivelul dorit de calitate a produsului.
Din standardul IEEE 730-1998, structura unui SQAP conține următoarele secțiuni:
Un exemplu de document SQAP puteți găsi aici.
Un proiect se poate finaliza în următoarele contexte:
Feluri de terminare a unui proiect:
În cazul în care se folosește un sistem de bug/issue tracking, trebuie ca toate issue-urile să fie rezolvate înainte de finalizarea proiectului chiar dacă ele nu au fost incluse în specificații.
În cazul în care nu se poate acest lucru, cei care predau proiectul trebuie să se asigure că problemele rămase deschise sunt de prioritate scăzută și nu au un impact major asupra funcționalității.
Încheierea unui proiect nu presupune numai livrarea produsului, ci și oportunitatea de a învăța din această experiență pentru îmbunătățirea contribuțiilor la proiectele viitoare.
Recomandări:
PPA:
Procesul PPA are următorii pași:
În general, se folosește un chestionar pentru colectarea informațiilor. De obicei, acesta are conținut diferit între team leaderi și team memberi.
Câteva întrebări de chestionar sunt cele de mai jos:
Un exemplu complet de chestionar găsiți aici
- Se dau următorul patch: patch și următorul tweet: tweet. Studiati-le timp de 5 minute. Vor fi importante pentru testul nostru Kahoot :) Nota: fiecare răspuns corect valorează un punct, se acordă un punct pentru prezență. Punctajul total aferent laboratorului curent este de 11p.
- Descrieți sumar conținutul unui SQAP pentru proiectul vostru.
- Pregătiți un checklist pentru terminarea proiectului vostru. Argumentați!
- Răspundeți la întrebările de la procesul PPA pentru proiectul vostru.
Stabiliti ce mai aveti de facut pentru finalizarea proiectelor.