This shows you the differences between two versions of the page.
icalc:laboratoare:laborator-09 [2023/05/14 19:41] dragos.isopencu |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laborator 09 - Regression & System Testing ===== | ||
- | |||
- | ==== Regression testing ==== | ||
- | |||
- | Testarea prin regresie este un tip de testare folosit pentru a determina o bucată de cod nouă va avea afecta negativ alte părți ale codului pe care nu le modifica în mod direct. În mod normal, atunci când introducem cod nou într-un modul al unui proiect, există teste unitare care verifică buna funcționare a modulului respectiv. Slăbicunea acestei metode este că nu verifică și posibilele efecte laterale ale noului modul. Astfel, testarea prin regresie este caracterizată prin testarea noului modul în contextul întregului proiect. | ||
- | |||
- | Testare prin regresie poate fi făcută în 3 moduri: | ||
- | - Retest all | ||
- | - Regression test selection | ||
- | - Prioritization of test cases | ||
- | |||
- | === Retest all === | ||
- | Cea mai costisitoare metodă, implică rerularea tuturor testelor aferente proiectului. Este de dorit să evităm această metodă pe cât posibil deoarece cosnumă foarte mult timp și resurse. | ||
- | === Regression test selection === | ||
- | Implică împărțirea testelor deja existente în suită în 2 categorii: cele care pot fi rulate pentru regresie și cele care nu sunt necesare pentru testarea prin regresie. | ||
- | === Prioritization of test cases === | ||
- | Testele sunt proritizate după impactul pecare îl are componenta testată în proiect. Componentele ale căror funcționalități sunt folosite des și/sau sunt critice sistemului vor avea o prioritate mai mare. | ||
- | |||
- | |||
- | ==== System testing ==== | ||
- | Dacă în ultimul laborator am discutat despre cum testele de integrare sunt folosite pentru a garanta că două componente interacționează corespunzător, în acest laborator vom discuta despre testarea întregului sistem. De regulă, testarea de sistem se face doar atunci când toate modulele sunt complete și integrate corespunzător, deoarece implică testarea cap-coadă a tuturor funcționalităților proiectului. Bineînțeles, acest tip de testare este necesar și pentru a verifica dacă proiectul final poate fi compilat cu succes. | ||
- | |||
- | |||
- | ==== Fuzz testing ==== | ||
- | Fuzz testing este o metodă de testare automată în care introducem în program input-uri invalide sau neașteptate pentru a monitoriza comportamentul acestuia. Acest tip de testare este predominant folosit pentru a testa securitatea unui sistem critic, prin a simula input-urile neobișnuite care ar putea duce la o breșă de securitate sau la brick-uirea sistemului. | ||
- | |||
- | {{ :icalc:laboratoare:fuzzing.png?600 |}} | ||
- | |||
- | De regulă, fuzzing-ul este făcut de către un fuzzer, care este un program extern ce generează input-urile eronate de care avem nevoie. Primul instinct atunci când auzim ce face un fuzzer ar putea fi să ne întrebăm "De ce am avea nevoie de un generator extern de input cand noi deja știm ce vrem de la cod?". Să luăm drept exemplu o funcție foarte simplă care calculează media: | ||
- | |||
- | <code teraterm> | ||
- | def compute_avg(data): | ||
- | return sum(data) / len(data) | ||
- | </code> | ||
- | Deși este un cod incredibil de simplu, el poate genera 4 erori diferite: | ||
- | - Dacă data nu este iterabil, sum va genera TypeError | ||
- | - Dacă data nu este o colecție, len va genera TypeError | ||
- | - Dacă data are lungime 0, diviza va genera ZeroDivisionError | ||
- | - Dacă data are prea multe elemente, len va genera OverfloError | ||
- | |||
- | Așadar, răspunsul la întrebarea "De ce am genera input automat" este "Pentru că există prea multe tipuri de input greșit" | ||
- | |||
- | Pentru acest laborator vom folosi fuzzer-ul atheris. | ||
- | <note tip><code teraterm> | ||
- | $pip install atheris | ||
- | </code></note> | ||
- | |||
- | |||
- | |||
- | |||
- | Example code: | ||
- | <code teraterm> | ||
- | import atheris | ||
- | import sys | ||
- | |||
- | @atheris.instrument_func | ||
- | def TestOneInput(data): | ||
- | # Need to prefix the string with 'b' because atheris | ||
- | # only works with bytes and not Unicode | ||
- | if data == b"bad": | ||
- | raise RuntimeError("VERY BAD!!!") | ||
- | |||
- | atheris.Setup(sys.argv, TestOneInput) | ||
- | atheris.Fuzz() | ||
- | </code> | ||
- | |||
- | Output: | ||
- | |||
- | {{:icalc:laboratoare:result_atheris.jpeg?600|}} | ||
- | |||
- | În același fișier în care se află executabilul atheris va genera un nou fișier text cu numele hash-ului generat, în care va scrie input-urile care au dus la generarea erorilor. În cazul de mai sus va crea dun fișier care conține doar cuvântul "bad" | ||
- | |||
- | Pentru a-i putea spune lui atheris care părți din cod trebuie instrumentate. Pentru a face acest lucru avem 3 opțiuni: | ||
- | |||
- | Pentru a instrumenta o anumită funcție: | ||
- | <code teraterm> | ||
- | with atheris.instrument_imports(): | ||
- | import some_lib | ||
- | from another_lib import random_feature | ||
- | </code> | ||
- | |||
- | Pentru a instrumenta biblioteci importate: | ||
- | <code teraterm> | ||
- | @atheris.instrument_func | ||
- | def my_func(my_input): | ||
- | print("instrumented") | ||
- | </code> | ||
- | |||
- | Pentru a instrumenta tot ce poate fi instrumentat: | ||
- | <code teraterm> | ||
- | atheris.instrument_all() | ||
- | atheris.Setup() | ||
- | </code> | ||
- | |||
- | ==== Exerciții ==== | ||
- | |||
- | |||
- | |||