Differences

This shows you the differences between two versions of the page.

Link to this comparison view

icalc:laboratoare:laborator-05 [2023/03/28 16:04]
dragos.sandulescu97 [Exerciții ​]
— (current)
Line 1: Line 1:
-===== Laborator ​05 - Unit Testing ​===== 
  
- 
-==== Software testing ​==== 
- 
-=== Clasificare ​==== 
- 
-Tipurile de testare software pot fi clasificate în linii mari ca testare statică și testare dinamică. În ceea ce privește testarea **//​statică//​**,​ documentele proiectului software sunt revizuite pentru a identifica erorile. În testarea **//​dinamică//​**,​ software-ul este testat în timpul execuției. Testarea dinamică poate fi white-box testing (am acces la cod -  testez o zona specifică) sau black-box testing (nu am acces la cod - testez output general pentru un input specific). 
- 
-{{:​icalc:​laboratoare:​ic_lab5_clasificare.png?​600|}} 
- 
-Cele două tipuri de testare **//​white-box//​** sunt **//​testarea unitară//​** și **//​testarea de integrare//​**. Testarea white-box este denumită și **//testare structurală//​**. **//​Testarea unitară//​** sau testarea componentelor testează fiecare componentă a programului în mod izolat. **//​Testarea de integrare//​** reprezintă un mod de a testa interfețele dintre componentele programului - a testa modul în care anumite feature-uri interacționează între ele. 
- 
-Cel de-al doilea tip de testare dinamică este testarea **//​black-box//​** - numită si testare bazată pe **//​specificații//​**. **//​Testarea sistemului//​** și **//​testarea de acceptanță a utilizatorului//​** (UAT) sunt cele două moduri de testare black-box. **//​Testarea sistemului//​** se bazează pe testarea întregului sistemul si a modului său de funcționare. **//​Testarea de acceptanță//​** determină în ce măsură o aplicație îndeplinește nevoile utilizatorilor finali. 
- 
-=== Unit testing ​==== 
- 
-Un test unitar reprezintă o modalitate de a **//testa o unitate//** - cea mai mică bucată de cod care poate fi izolată logic dintr-un sistem. În majoritatea limbajelor de programare, aceasta este o funcție, o subrutină, o metodă sau o proprietate. În ceea ce privelte paradigma orientată pe obiecte, unitatea care urmează să fie supusă testării este adesea o clasă, o interfață sau o metodă. 
- 
-<note tip> 
-Testarea unitară este un pas important în procesul de dezvoltare, deoarece, dacă este făcută corect, poate ajuta la **//​detectarea din timp a bug-urilor//​**,​ care pot fi mai dificil de găsit în etapele ulterioare de testare. 
-</​note>​ 
- 
-Testarea unitară este o componentă a **//​dezvoltării bazate pe testare (TDD)//** - o abordare prin dezvoltarea unui produs prin intermediul testării și revizuirii continue. Această metodă de testare este, de asemenea, primul nivel de testare a software-ului,​ care este efectuat înaintea altor metode de testare, cum ar fi testarea de integrare. Testele unitare sunt de obicei izolate pentru a se asigura că o unitate nu se bazează pe altă bucată de cod sau funcții externe. 
- 
- 
-==== pytest ​==== 
- 
- 
-PyTest este un framework de testare care permite utilizatorilor să scrie teste folosind limbajul de programare Python. Oferă o funcționalitate completă care permite scrierea de teste unitare simple până la teste funcționale complexe. 
- 
-{{:​icalc:​laboratoare:​ic-lab5-2.png?​600|}} 
- 
-Pytest spre deosebire de bilioteca default de testare oferită de Python - [[https://​docs.python.org/​3/​library/​unittest.html|unittest]] - oferă o flexibilitate și o putere mai mare de testare. 
- 
-<note tip> 
-Documentația oficială pytest: https://​docs.pytest.org/​en/​7.2.x/​ 
-</​note>​ 
- 
-=== Set-up === 
- 
-== Instalare python == 
-Pentru Ubuntu: 
-<code teraterm>​ 
-$ sudo apt install python3 
-</​code>​ 
- 
-Pentru Windows: 
- 
-https://​www.python.org/​downloads/​ 
- 
-<note tip> 
-Asigurați-vă ca aveti versiunea de //​**python3.7+**//​ 
-<code teraterm>​ 
-$ python3 --version 
-</​code>​ 
-</​note>​ 
- 
-== Instalare pytest == 
-Pentru Ubuntu: 
-<code teraterm>​ 
-$ sudo apt install python3-pip 
- 
-$ pip3 install pytest 
-</​code>​ 
- 
-Pentru Windows: 
- 
-Deschide o instanță de **//cmd//** 
- 
-<code teraterm>​ 
-$ pip3 install pytest 
-</​code>​ 
- 
-=== Creare primului test === 
- 
-Pentru ca pytest să recunoască un fișier de test, acesta trebuie să conțină prefixul **test_** (e.g. test_factorial.py). De asemenea, și metoda trebuie să conțină prefixul **test_** (e.g. def test_i_love_ic()). 
- 
-<code python> 
-# content of test_IC.py 
- 
-def increment(x):​ 
-    return x + 1 
- 
-def test_increment():​ 
-    assert increment(3) == 4 
-</​code>​ 
- 
-Pentru a rula pytest pentru fișierul anterior: 
-<code teraterm>​ 
-$ pytest test_IC.py 
-</​code>​ 
- 
-<note tip> 
-În cazul în care aveți mai multe fișiere de test și doriți execuția tuturor testelor, se execută doar comanda de pytest. 
-<code teraterm>​ 
-$ pytest 
-</​code>​ 
- 
-În cazul în care doriți să rulați un test specific, folosiți 
-<code teraterm>​ 
-$ pytest $NUME_FISIER.py::​$NUME_TEST 
- 
-$ pytest test_IC.py::​test_increment 
-</​code>​ 
- 
-Un flag important pentru pytest este -k care primește ca input un string și rulează doar testele care se potrivesc cu secvența string. 
-<code teraterm>​ 
-$ pytest -k <​substring>​ 
- 
-$ pytest -k increment 
-</​code>​ 
- 
-</​note>​ 
- 
-Exemplu output test - passed 
-<code teraterm>​ 
-================================================= test session starts ================================================== 
-platform linux -- Python 3.10.6, pytest-7.2.2,​ pluggy-1.0.0 
-rootdir: $PATH 
-collected 1 item 
- 
-test_IC.py .                                                                                                     ​[100%] 
- 
-================================================== 1 passed in 0.09s =================================================== 
-</​code>​ 
- 
-Exemplu output test - failed 
- 
-<code teraterm>​ 
-================================================= test session starts ================================================== 
-platform linux -- Python 3.10.6, pytest-7.2.2,​ pluggy-1.0.0 
-rootdir: $PATH 
-collected 1 item 
- 
-test_IC.py F                                                                                                     ​[100%] 
- 
-======================================================= FAILURES ======================================================= 
-____________________________________________________ test_increment ____________________________________________________ 
-    def test_increment():​ 
->       ​assert increment(3) == 5 
-E       ​assert 4 == 5 
-E        +  where 4 = increment(3) 
- 
-test_IC.py:​5:​ AssertionError 
-=============================================== short test summary info ================================================ 
-FAILED test_IC.py::​test_increment - assert 4 == 5 
-================================================== 1 failed in 0.15s =================================================== 
-</​code>​ 
- 
-=== Assert statements === 
- 
-**1. Equal to or not equal** 
-<code python> 
-assert 5 == 5 || assert 5 != 3 # Success Examples 
-assert 5 == 3 || assert 5 != 5 # Fail Examples 
-</​code>​ 
- 
-**2. type()** 
-<code python> 
-assert type(5) is int # Success Example 
-assert type(5) is not int # Fail Example 
-</​code>​ 
- 
-**3. isinstance** 
-<code python> 
-assert isinstance('​5',​ str) # Success Example 
-assert isinstance('​5',​ int) # Fail Example 
-</​code>​ 
- 
-**4. Boolean ** 
-<code python> 
-truth_variable = 5 == 5 
-assert truth_variable is True # Success Example 
-assert truth_variable is False # Fail Example 
-</​code>​ 
- 
-**5. in and not in ** 
-<code python> 
-note_IC = [10, 4, 9, 9] 
-assert 10 in note_IC || assert 5 not in note_IC # Success Examples 
-assert 10 not in note_IC || assert 7 in note_IC # Fail Examples 
-</​code>​ 
- 
-**6. Greater than or less than ** 
-<code python> 
-assert 5 > 4 # Success Example 
-assert 5 > 7 # Fail Example 
-</​code>​ 
- 
-**7. any() | all() ** 
-<code python> 
-note_IC = [10, 4, 9, 8, 7] 
-trecut_IC = [True, False, True, True, True] 
- 
-assert any(note_IC) == True # Success Example => cel putin un element din lista este diferit de 0. 
-assert any(trecut_IC) == True # Success Example => cel putin un element din lista este True. 
- 
-assert all(note_IC) # Success Example => toate elementele din lista sunt diferite de 0. 
-assert all(trecut_IC) # Fail Example => nu toate elementele din lista sunt True. 
-</​code>​ 
- 
-**8. Exception ** 
-<code python> 
-def function(): 
-    raise SystemExit(1) 
- 
- 
-def test_mytest():​ 
-    with pytest.raises(SystemExit):​ 
-        function() 
-</​code>​ 
- 
-=== Marks === 
- 
-Marks pot fi folosite pentru aplicarea meta datelor la funcțiile de testare. Markerii sunt utilizați pentru a seta diverse caracteristici/​atribute pentru a testa anumite funcționalități. 
- 
-Markerii sunt declarați folosind următoarea sintaxă: 
-<code python> 
-@pytest.mark.<​markername>​ 
-</​code>​ 
- 
-Acest lucru ne permite gruparea testelor si rularea lor in anumite batch-uri 
-<code python> 
-groceries = ["​Potatoes",​ "​Onions",​ "​Flowers"​] 
- 
-@pytest.mark.veggies 
-def test_potatoes_in_list():​ 
-   ​assert '​Potatoes'​ in groceries 
-    
-@pytest.mark.veggies 
-def test_onions_in_list():​ 
-   ​assert '​Onions'​ in groceries 
- 
-@pytest.mark.others 
-def test_flowers_in_list():​ 
-   ​assert '​Flowers'​ in groceries 
-</​code>​ 
- 
-Pentru a rula o suită de deste marcate cu un anumit marker, se folosește comanda: 
- 
-<code teraterm>​ 
-$ pytest -m <​markername>​ -v 
-</​code>​ 
- 
- 
-Pytest oferă o serie de marks deja implementate pentru a facilita testarea. 
- 
-**pytest.mark.skip** 
- 
-<code python> 
-# https://​docs.pytest.org/​en/​7.2.x/​reference/​reference.html#​pytest-mark-skip 
- 
-@pytest.mark.skip(reason="​I have no idea how to test this") 
-def test_the_great_unknown():​ 
-    ... 
-</​code>​ 
- 
-**pytest.mark.skipif** 
- 
-<code python> 
-# https://​docs.pytest.org/​en/​7.2.x/​reference/​reference.html#​pytest-mark-skipif 
- 
-@pytest.mark.skipif(sys.platform == "​Linux",​ reason="​Tests for Windows only!"​) 
-def test_function():​ 
-    ... 
-</​code>​ 
- 
-**pytest.mark.xfail** - atunci când ne așteptăm ca un test să întoarcă fail. xfail marchează testul ca fiind de așteptat să eșueze. 
- 
-<code python> 
-# https://​docs.pytest.org/​en/​7.2.x/​reference/​reference.html#​pytest-mark-xfail 
- 
-def add_two_ints(a,​ b): 
-    return a + b 
-    ​ 
-@pytest.mark.xfail(reason="​Missing Arguments"​) ​   ​ 
-def test_add_two_ints_xfail_missing_arg() -> None:  ​ 
-    value = add_two_ints(10) ​ # Missing Argument - FAIL  ​ 
-    assert value == 10 
-    ​ 
-...    ​ 
- 
-@pytest.mark.xfail(sys.platform == "​win32",​ reason="​bug with the checkout",​ raises=RuntimeError) 
-def test_function():​ 
-    ...  
-</​code>​ 
-<note tip> 
-Găsiți mai multe exemple de test skipping în documentația oficială: https://​docs.pytest.org/​en/​7.1.x/​how-to/​skipping.html 
-</​note>​ 
- 
-**pytest.mark.parametrize** - permite definirea mai multor seturi de argumente pentru funcția sau clasa de testare. Așadar, parametrizarea unui test se face pentru a rula testul pe mai multe seturi de intrări. 
- 
-<code python> 
-@pytest.mark.parametrize("​number,​ output",​ [(1, 2), (2, 3), (3, 6), (4, 5)]) 
-def test_incrementation(number,​ output): 
-   ​assert number + 1 == output 
-    
-@pytest.mark.parametrize("​a,​ b, expected",​ [(1, 2, 4), (3, 4, 9)]) 
-def test_i_wish_i_was_rich(a,​ b, expected): 
-    assert 2 * a + b == expected 
-</​code>​ 
- 
-Parametrizare unei **//​clase//​** se poate realiza astfel: 
-<code python> 
-import pytest 
- 
-@pytest.mark.parametrize("​number,​ expected",​ [(1, 2), (3, 4)]) 
-class TestClass: 
-    def test_increment(self,​ number, expected): 
-        assert number + 1 == expected 
- 
-    def test_increment_with_extra_steps(self,​ number, expected): 
-        assert (number * 1) + 1 == expected 
-</​code>​ 
- 
-<note tip> 
-Dacă dorim parametrizarea tuturor testelor dintr-un modul, atunci putem realiza acest lucru prin initializarea **pytestmark** ca variabilă globală 
-<code python> 
-import pytest 
- 
-pytestmark = pytest.mark.parametrize("​n,​expected",​ [(1, 2), (3, 4)]) 
- 
-class TestClass: 
-    def test_increment(self,​ n, expected): 
-        assert n + 1 == expected 
- 
-    def test_increment_with_extra_steps(self,​ n, expected): 
-        assert (n * 1) + 1 == expected 
-</​code>​ 
-</​note>​ 
- 
-=== Fixtures - Introducere === 
- 
-Fixtures sunt **funcții** atașate la teste **care rulează înainte ca funcția de testare să fie executată**. Fixtures sunt folosite pentru a furniza unele date la teste, cum ar fi conexiunile la baze de date, URL-urile de testat sau un fel de date de intrare. Prin urmare, în loc să rulăm același cod pentru fiecare test, putem atașa funcția de fixture la teste și va returna datele testului înainte de a executa fiecare test.  
- 
-Fixtures sunt un set de resurse care trebuiesc configurate înainte și curățate odată ce execuția testului este finalizată 
- 
-Funcția pytest fixture este apelată automat de framework-ul pytest atunci când numele argumentului și numele fixture-ului sunt același. 
- 
-O funcție este marcată ca element fixture folosind: 
-<code python> 
-@pytest.fixture 
-</​code>​ 
- 
-<note tip> 
-O funcție de testare poate folosi un fixture prin menționarea numelui fixture-ului ca parametru de intrare. 
-</​note>​ 
- 
-<code python> 
-@pytest.fixture 
-def fixture_function():​ 
-   ​return "IC is love, IC is life" 
-    
-    
-def test_fixture(fixture_function):​ 
-    assert fixture_function == "IC is love, IC is life" 
-</​code>​ 
- 
-<note tip> 
-Built-in fixtures: https://​docs.pytest.org/​en/​7.2.x/​reference/​fixtures.html#​fixture 
-</​note>​ 
- 
-Fixtures care sunt **autouse** se aplică fiecărui test care le-ar putea referi, fiind **executate înaintea tuturor**. 
- 
-Dacă fixture-ul A este autouse și fixture-ul B nu este, dar fixture-ul A solicită fixture-ul B, atunci fixture-ul B va fi efectiv și un fixture autouse, dar numai pentru testele cărora li se aplică A. 
- 
-Astfel, daca dorim executarea unei anumite logici înainte unui test, putem să realizăm acest lucru folosind autouse și scope. Scope marcheză modul în care fixture-urile pot să fie "​împărțite"​ (shared). Scope poate să fie: function, class, module, package or session. 
- 
-<code python> 
-@pytest.fixture(scope="​session",​ autouse=True) 
-def do_something_before_everyone():​ 
-    # do something ahead of all the tests 
-    ... 
-</​code>​ 
- 
-Dacă dorim a avea o logică specifică înainte(set-up) și după(tear-down) fiecare test: 
- 
-<code python> 
-import pytest 
- 
-@pytest.fixture(autouse=True) 
-def run_before_and_after_each_test():​ 
-    # Setup: logic that happens before the test 
- 
-    yield # this is where the testing happens 
- 
-    # Teardown: logic that happens after the test 
-</​code>​ 
- 
- 
-<note tip> 
-Requesting & Finalization & Autouse & Scope for fixtures & Mai multe moduri de utilizare fixtures: https://​docs.pytest.org/​en/​latest/​how-to/​fixtures.html 
-</​note>​ 
- 
-Trimiterea unui obiect catre test se poate realiza folosind fixture 
- 
-<code python> 
-import pytest 
- 
-class Student: 
-  def __init__(self,​ name, age, scholarship):​ 
-    self.name = name 
-    self.age = age 
-    self.scholarship = scholarship 
- 
-@pytest.fixture 
-def student(): 
-    student = Student("​Mr. Perfect",​ 20, True) 
- 
-    return student 
- 
-def test_student_creation(student):​ 
-    assert student.name == "Mr. Perfect"​ 
- 
-    assert student.age == 20 
- 
-    assert student.scholarship is True 
- 
-    assert isinstance(student,​ Student) 
-</​code>​ 
- 
- 
-==== Exerciții ​==== 
- 
- 
-{{:​icalc:​laboratoare:​1.gif?​300|}} 
- 
-1 [**4p**]. 
-  * A [**2p**] Creați un fisier de test pentru factorial.py. Creați un test care să verifice că funcția factorial întoarce output-ul corect pentru un input introdus de voi. 
-  * B [**2p**] În fisierul creat anterior: 
-    * Scrieți un test care să primească mai multe input-uri consecutive pentru funcția factorial. 
-<note tip>P A R A M E T R I Z E 
- ( ͡° ͜ °) 
-</​note>​ 
-    * Scrieți un test care să valideze aruncarea unei excepții în cazul în care se introduce ca input o valoare incorectă. 
- 
-2 [**6p**]. 
-  * A [**0.5p**] 
-  * B [**1p**] 
-  * C [**1p**] 
-  * D [**1.5p**] 
-  * E [**1p**] 
-  * F [**1p**] 
- 
-Bonus [**2p**] 
icalc/laboratoare/laborator-05.1680008662.txt.gz · Last modified: 2023/03/28 16:04 by dragos.sandulescu97
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0