01 Uči
Ručne provere su korisne. Automatske provere pamte.
Već si ručno pokretao TaskManager metode u main.py. To je korisno dok gradiš projekat, ali svaka kasnija izmena može zahtevati ponavljanje istih provera. Automatski test beleži jedno očekivanje i omogućava Pythonu da ga ponovo proveri svaki put kada pokreneš testove.
import unittest
class TestTaskManager(unittest.TestCase):
def setUp(self):
self.manager = TaskManager()
self.task = Task("task-1", "Read the plan")
self.manager.add_task(self.task)
def test_complete_task_marks_task_complete(self):
self.manager.complete_task("task-1")
self.assertTrue(self.task.completed)
unittest je deo Python standardne biblioteke, zato instalacija nije potrebna. Klasa izvedena iz unittest.TestCase grupiše povezane testove. Svaki metod čije ime počinje sa test_ biće pronađen i pokrenut.
python3 -m unittest -v
# or: python -m unittest -v
setUp() pravi nov menadžer i zadatak pre svakog test metoda. Tako testovi ostaju nezavisni: jedan test ne može slučajno da ostavi promenjeno stanje za sledeći.
↳Jedno očekivanje odjednom: assertEqual() upoređuje stvarnu vrednost sa očekivanom vrednošću. assertTrue() proverava da li je uslov True. Neuspešna provera je korisna informacija: najpre odluči da li je pogrešan kod ili očekivanje.
Testiraj očekivanu greškuwith self.assertRaises(ValueError):
self.manager.get_task("missing-task")
assertRaises() prolazi samo kada se dogodi očekivani ValueError. Koristi ga za task_id koji nedostaje tek nakon što odlučiš da je ValueError pravilo projekta.
Testiraj ponašanje, a ne detalje implementacijeself.assertTrue(self.task.completed)
Test za complete_task() može da proveri da li completed postaje True. Ne mora da zna koliko unutrašnjih linija koda metod koristi.
Pokreni testove iz foldera projektapython -m unittest
Stavi testove u jasno nazvan test fajl i pokreni python -m unittest iz foldera Task Manager projekta. Pokretač testova pronalazi metode koje počinju sa test_.
Odvoji JSON testove od stvarnih podatakamanager.save_tasks(test_path)
Kasnije prosledi malu privremenu putanju metodama save_tasks(path) i load_tasks(path) za JSON provere. Test nikada ne sme da prepiše data/tasks.json fajl koji koristiš dok učiš.
Mala rutina testiranja
- Pripremi poznate podatkeNapravi TaskManager i Task vrednosti koje testu trebaju, najčešće u setUp().
- Izvrši jednu radnjuPozovi jednu TaskManager metodu, kao što su complete_task() ili get_task().
- Proveri rezultatKoristi assertEqual(), assertTrue() ili assertRaises() da uporediš stvarno ponašanje sa jednim jasnim očekivanjem.
Česte greške pri testiranju Task Managera
- Testovi zavise od ranijeg testaNemoj pretpostaviti da je drugi test već dodao zadatak. Daj svakom testu njegovo poznato početno stanje pomoću setUp().
- Menjanje stvarnih podataka za učenjeNemoj usmeriti test na JSON fajl koji koristiš u svom običnom projektu. Prosledi posebnu putanju metodama save_tasks(path) i load_tasks(path) kada praviš izolovane privremene podatke za testiranje.
- Očekivanje greške bez provere pravilaKoristi assertRaises(ValueError) samo kada projekat namerno smatra taj ulaz neispravnim, na primer kada task_id ne postoji.
02 Radi lokalno
Testiraj svoj završeni Task Manager
Radi ovo u VS Code-u
Nastavi u raspakovanom folderu task_manager_starter iz koncepata 28–30. U dijagramima lekcije projekat se zove task_manager, ali treba da nastaviš da radiš u istom starter folderu. Napravi fokusirane testove za ponašanje koje si već izgradio; ne započinji novi projekat i ne preuzimaj novi ZIP.
Tvoj postojeći projekattask_manager/
├── main.py
├── models/
│ └── task.py
├── services/
│ └── task_manager.py
├── data/
│ └── tasks.json
└── tests/
├── __init__.py
└── test_task_manager.py
Nije potreban novi ZIP. Zadrži svoj funkcionalni Task Manager i dodaj tests paket pored aplikacionog koda, kako bi test fajlovi ostali odvojeni od main.py i servisa.
Napravi testove korak po korak
- Napravi tests paketU korenu projekta napravi tests/, prazan fajl tests/__init__.py i tests/test_task_manager.py. U test fajlu uvezi Task iz models.task i TaskManager iz services.task_manager.
from models.task import Task
from services.task_manager import TaskManager
import unittest
- Napiši jedan test za add_task()Koristi unittest.TestCase i setUp() da napraviš nov TaskManager i Task za svaki test. Pripremi poznate objekte, pozovi add_task(), zatim proveri da menadžer ima jedan zadatak i da je to Task koji si dodao.
class TestTaskManager(unittest.TestCase):
def setUp(self):
self.manager = TaskManager()
self.task = Task("task-1", "Read the plan")
- Testiraj operacije koje si već napravioDodaj fokusirane testove za get_task(), complete_task() i delete_task(). Počni sa jednim ponašanjem po testu: pronađi isti Task, postavi completed na True ili ukloni odgovarajući Task iz liste.
self.manager.complete_task("task-1")
self.assertTrue(self.task.completed)
- Testiraj očekivane ValueError slučajeveKoristi assertRaises(ValueError) za pravila projekta iz Concepta 29: duplirani task_id se odbija, a pronalaženje ili završavanje task_id-ja koji ne postoji podiže ValueError.
with self.assertRaises(ValueError):
self.manager.get_task("missing-task")
- Koristi privremenu JSON putanjuTemporaryDirectory pravi prazan folder koji Python uklanja kada se with blok završi. U njemu napravi test_path, zatim tu putanju prosledi metodama save_tasks(path) i load_tasks(path). Tako stvarni data/tasks.json fajl ostaje bezbedan.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temp_dir:
test_path = Path(temp_dir) / "tasks.json"
- Proveri čuvanje, učitavanje i zamenu listeSačuvaj zadatke na test_path, zatim ih učitaj u novi TaskManager. Proveri da su učitane stavke Task objekti. Dodaj jedan privremeni zadatak u memoriju pre učitavanja i potvrdi da uspešno učitavanje zamenjuje tu listu, umesto da joj dodaje stavke.
writer.save_tasks(test_path)
reader.load_tasks(test_path)
- Pokreni ceo skup testovaIz korena projekta pronađi svaki test u tests/. Pažljivo pročitaj prvi FAIL ili ERROR, zatim pregledaj imenovani test i njegovo očekivano ponašanje pre menjanja koda.
python -m unittest discover -s tests
# or: python3 -m unittest discover -s tests
Arrange → Act → Assert u tvom projektu# Arrange
self.manager.add_task(self.task)
# Act
found = self.manager.get_task("task-1")
# Assert
self.assertEqual(found, self.task)
Neka svaki test bude mali. Ovaj primer proverava samo da get_task() vraća Task sa traženim ID-jem; napiši posebne testove za završavanje i brisanje.
Tipičan rezultat u terminalu.......
----------------------------------------------------------------------
Ran 7 tests in 0.012s
OK
OK znači da je svaki test završen i da je svaka provera prošla. FAIL znači da provera nije odgovarala očekivanju. ERROR znači da je neočekivani problem zaustavio test pre završetka njegove provere.
↳Kontrolna lista završnog projekta: add → find → complete → delete → expected ValueError → save → load → test suite Potvrdi da osnovne operacije rade, da se očekivani izuzeci prijavljuju, da JSON čuvanje i učitavanje rade sa posebnom test putanjom, da testovi počinju nezavisno i da ceo skup prijavljuje OK.
Pre nego što zatražiš pomoć od Slobyja
- Ispravi importe pre menjanja testovaPokreni komandu iz korena projekta. Proveri da tests/__init__.py postoji i da importi tačno koriste models.task i services.task_manager.
- Imenuj fajlove i metode da bi bili pronađeniFajl treba da počinje sa test_, a svaki test metod sa test_. U suprotnom unittest možda neće da ga pokrene.
- Razlikuj FAIL i ERRORFAIL znači da se provera ne slaže sa rezultatom. ERROR znači da test nije mogao da se završi, često zbog importa, greške u kucanju ili neočekivanog izuzetka.
- Ukloni skrivene zavisnosti od redosleda testovaAko test prolazi sam, ali pada u celom skupu, proveri da setUp() pravi sve zadatke i menadžere koji su tom testu potrebni.
- Zaštiti svoj stvarni JSON fajlProsledi privremeni test_path metodama save_tasks(path) i load_tasks(path). Nikada ne usmeravaj test na svoj uobičajeni data/tasks.json fajl.
- Proveri očekivanu vrednostPre menjanja assertEqual(), odluči da li je pogrešna implementacija ili očekivani rezultat. Test treba da opiše pravilo projekta, a ne da sakrije grešku.
↳Sada si spojio klase, module, JSON fajlove, izuzetke i automatske testove u jednom lokalnom projektu. Završavanje kontrolne liste ne menja automatski tvoj napredak u učenju; koristi je kao dokaz onoga što možeš da objasniš i proveriš.