Funcții care ridică excepții
O funcție Python care primește date de intrare greșite trebuie să semnaleze acest lucru ridicând o excepție: la succes returnează rezultatul, la eșec ridică o eroare — de exemplu ValueError — care explică ce nu a mers.
Un test pentru o astfel de funcție trebuie să verifice ambele căi: datele corecte returnează valoarea potrivită și nu ridică nimic, iar datele greșite chiar ridică o excepție — o funcție care acceptă în tăcere date greșite este tot o eroare.
pytest.raises este instrumentul pentru calea greșită: un bloc with care face testul să eșueze dacă din el nu iese excepția așteptată.
Calea corectă
Pentru date de intrare valide nu trebuie scris nimic în plus. Apelează funcția, apoi compară valoarea. Dacă apelul ridică totuși o excepție, excepția încheie singură testul și raportul o arată — nu trebuie să o verifici mai întâi.
Date valide, fără excepție
safe_divide(10, 2) trebuie să returneze 5 și să nu ridice nicio excepție. Apelul vine primul; o excepție neașteptată ar încheia testul chiar acolo. Abia apoi se compară valoarea.
Ieșire: program Python complet
def safe_divide(a, b):
if b == 0:
raise ValueError("nu se poate împărți la zero")
return a / b
def test_safe_divide_good():
got = safe_divide(10, 2)
assert got == 5
Calea greșită
Cealaltă jumătate a contractului: datele greșite trebuie să ridice o excepție. Apelul se pune într-un bloc with pytest.raises(ValueError) — dacă funcția returnează un număr în loc să ridice excepția, testul eșuează.
Contează să numești clasa excepției: blocul acceptă doar un ValueError, așa că o altă eroare, neașteptată, face în continuare testul să eșueze.
Datele greșite trebuie să ridice o excepție
Împărțirea la zero trebuie să eșueze. pytest.raises(ValueError) învelește apelul safe_divide(10, 0). Funcția ridică excepția promisă, așa că testul trece.
Ieșire: program Python complet
import pytest
def safe_divide(a, b):
if b == 0:
raise ValueError("nu se poate împărți la zero")
return a / b
def test_safe_divide_by_zero():
with pytest.raises(ValueError):
safe_divide(10, 0)
Un tabel cu want_error
Ambele căi încap într-un singur test parametrizat: dă fiecărui caz un indicator want_error care spune dacă se așteaptă o excepție. Valoarea want este None pentru acel caz, pentru că un caz care ridică o excepție nu are nicio valoare de comparat.
Testul se uită mai întâi la want_error. Eșecul așteptat se verifică cu pytest.raises și testul se oprește acolo; celelalte cazuri compară valoarea ca de obicei.
Cazuri corecte și greșite într-un singur tabel
Patru cazuri: trei împărțiri obișnuite și o împărțire la zero cu want_error=True. Un singur test parametrizat acoperă întregul contract al funcției, iar toate cele patru cazuri trec.
Ieșire: program Python complet
import pytest
def safe_divide(a, b):
if b == 0:
raise ValueError("nu se poate împărți la zero")
return a / b
@pytest.mark.parametrize("a, b, want, want_error", [
(10, 2, 5, False),
(-9, 3, -3, False),
(0, 5, 0, False),
(10, 0, None, True),
], ids=["simple_division", "negative_result", "divide_zero", "divide_by_zero"])
def test_safe_divide(a, b, want, want_error):
if want_error:
with pytest.raises(ValueError):
safe_divide(a, b)
else:
assert safe_divide(a, b) == want