11.1 Miért írunk teszteket? – A biztosítás metafora
Áttekintő
Ha valaha megváltoztattál egy kódrészletet, majd szorongva nézted, hogy vajon elromlott-e valami máshol – pontosan azt érzed, amit az automatizált tesztek kiváltanak. Ez az alfejezet nem arról szól, hogy megtanítson tesztelni – arról szól, hogy megértsd: miért érdemes egyáltalán teszteket írni, és mit vársz tőlük reálisan.
A teszt nem a fejlesztés ellenfele. Nem a bürokratikus overhead. Nem valami, amit a seniorok csak azért követelnek, mert „így szokás". A teszt a jövőbeli önmagad biztosítása – és ahogy egy lakásbiztosításra sem gondolsz minden nap, de hálás vagy, ha szükség van rá, ugyanúgy fog működni ez is.
Részletes leírás
A biztosítás metafora – miért pont ez?
Képzelj el két szituációt:
Szituáció A: Írsz egy funckiót, ami kiszámolja egy rendelés végösszegét. Majd 3 hónappal később kollégád hozzányúl, hogy kezelni tudja a kuponkódokat. Ő nem tudja, hogy te a végösszeg kiszámításában elrejtettél egy edge case-t: ha az ár nulla, ne kerüljön ki a számlából a kedvezmény. Nincs teszt. Ő nem is tud erről az esetről. Deploy. Production hiba. Dühös ügyfél.
Szituáció B: Ugyanaz a szituáció, de te írtál egy tesztet az edge case-re. Kolléga módosít. A teszt elbukik. Kolléga megkérdezi: „Mi ez a teszt?" Megnézi, megérti a logikát, javítja. Deploy. Nincs production hiba.
Ez a biztosítás. Nem boldogabbá teszi az életet – de megakadályozza a katasztrófát.
Mire jó valójában a teszt?
1. Regressziók felismerése
A „regresszió" szó azt jelenti: valami, ami korábban működött, elromlott. Ezek a legkellemetlenebb hibák, mert nem az új kódban keresed – hanem a régiben, amit véletlenül eltörtél.
Tesztek nélkül a regressziók vagy:
- Ismeretlenek maradnak (és production-ban derül ki)
- Manuálisan kell végigkattintani minden funkciót minden deploy előtt
Tesztekkel a CI pipeline automatikusan szól, ha valami eltört.
2. Refactoring félelem feloldása
Az egyik legnagyobb szimptóma, hogy egy codebase baj van: senki nem meri refaktorálni. Mindenki tudja, hogy a kód csúnya, de senki nem nyúl hozzá, mert „mi lesz, ha elromlik valami?"
Ez a refactoring paralízis. Ha van tesztlefedettség, bátran átírhatod a belsőt – amíg a tesztek zöldek, a viselkedés nem változott.
3. Dokumentáció mellékhatásként
Egy jól megírt teszt pontosan leírja, mire számítasz egy adott szituációban. Pl.:
def test_discount_not_applied_when_price_is_zero():
order = Order(price=0)
order.apply_coupon("SUMMER20")
assert order.total == 0
Ez egy mondatnyi üzleti logika, amit bárki megért – kód olvasása nélkül. A teszt neve maga a dokumentáció.
4. Tervezés segítése
Ha a tesztet a kód előtt írják (erről szól majd a 11.3-as alfejezet), akkor a teszt a design eszköze is lesz. „Hogyan akarom ezt a funkciót meghívni?" – ez a kérdés kényszeríti ki a tiszta interfészeket.
Mikor NEM éri meg tesztet írni?
Ez az a pont, ahol a legtöbb anyag hazudik. Nem kell mindent tesztelni. Néhány eset, ahol a teszt értéke kérdéses:
Sokat változó, kísérletező kód
Ha egy feature prototípusát írod, és 80% eséllyel kukázod holnap, a teszt overhead. Tesztelj, ha a kód stabil és marad.
Triviális getter/setter
def get_name(self):
return self.name
Ennek a tesztelése ceremony, nem értékteremtés. Ha a framework generálta, bízz benne.
UI layout részletek
Pixel-perfect tesztelés törékeny. Ha az elemek pozíciója változik, a teszt folyton elbukik okos ok nélkül. Inkább integrációs tesztek.
Egyszeri script
Ha valami egyszer fut le és eldobandó, tesztelés felesleges overhead.
Realista elvárások – mit NE várj a tesztektől
- A teszt nem találja meg az összes bugot. Csak azokat, amikre írtál tesztet.
- A teszt nem helyettesíti a code review-t. A logikailag rossz kód átmehet teszteken.
- 100% coverage nem = hibamentes kód. Erről részletesen a 11.5-ös alfejezetben.
- A tesztek is el tudnak romlani. Törékeny tesztek több bajt okoznak, mint hasznot (11.7).
Életszerű példák
Példa 1: Az éjféli deploy és a néma regresszió
Lili junior fejlesztő egy e-commerce projekten dolgozik. Kap egy ticketet: „Add hozzá az ingyenes szállítás logikáját 20.000 Ft felett." Megírja, kézzel leteszteli, működik. Deploy pénteken este.
Hétfőn reggel: az ügyfélszolgálat jelzi, hogy minden rendelésnél hibás az összeg. Kiderül: a szállítási költség számítása az order.total property-t hívja, amit Lili módosított a logikában. Nincs teszt, nincs visszajelzés. Hotfix-ek, stressz.
Ha lett volna egy teszt az order.total eredeti viselkedésére, a CI megállítja a deploy-t.
Példa 2: A félelmetes legacy modul
Péter csatlakozik egy 5 éves projekthez. Van egy pricing_engine.py nevű fájl, amit senki nem mer megnyitni. „Nem tudjuk, mit csinál pontosan, de működik" – mondják a kollégák.
Seniorja megkéri Pétert: írja le, amit megért belőle, tesztekbe. 2 nap alatt Péter teszteket ír, miközben megérti a logikát. Most:
- Dokumentálva van, mit csinál
- Bárki módosíthatja anélkül, hogy mindent félne
- A refaktorálás megkezdődhet
Példa 3: Az interjú kérdés
Állásinterjún a senior megkérdezi: „Hogyan biztosítod, hogy a módosításod nem törte el az existing functionality-t?"
Teszt nélküli junior válasz: „Kézzel leteszteltem a főbb use case-eket."
Teszt-tudatos junior válasz: „Volt meglévő tesztsuite, ami lefutott. Ahol nem volt teszt, írtam egyet az érintett logikára, hogy a viselkedés dokumentált legyen."
A második válasz nem csak jobb technikai döntést mutat – azt jelzi, hogy a jelölt team-player, mert gondol a jövőbeli kollégákra is.
Tesztfeladatok
1. kérdés
Miért hívja ez az alfejezet a teszteket „biztosításnak"?
A) Mert drágák, mint a biztosítás
B) Mert nem boldogítanak naponta, de megakadályozzák a katasztrófát, amikor szükség van rájuk
C) Mert kötelező minden cégnél rendelkezni velük
D) Mert mindig 100%-ban megvédik a hibáktól
Helyes válasz: B
2. kérdés
Mi az a „regresszió" a szoftverfejlesztésben?
A) Régi kód újraírása modernebb technológiával
B) Olyan hiba, ami egy korábban működő funkciót elront
C) A kód visszafelé kompatibilitásának elvesztése
D) Teljesítményromlás az alkalmazásban
Helyes válasz: B
3. kérdés
Melyik állítás igaz a tesztek dokumentációs szerepéről?
A) A tesztek teljes mértékben helyettesítik a kóddokumentációt
B) Egy jól megnevezett teszt leírja, milyen viselkedést vár el egy adott szituációban
C) A tesztek csak a fejlesztőknek nyújtanak információt, nem az üzleti logikáról
D) Dokumentációs célra a kommentek hatékonyabbak, mint a tesztek
Helyes válasz: B
4. kérdés
Melyik esetben NEM éri meg általában tesztet írni?
A) Komplex üzleti logikánál
B) Régi kód refaktorálásánál
C) Prototípusnál, amit valószínűleg hamarosan eldobunk
D) Kritikus számítási funkciónál
Helyes válasz: C
5. kérdés
Mi a „refactoring paralízis"?
A) Amikor a fejlesztő nem tudja, hogyan kell refaktorálni
B) Amikor senki nem meri átírni a kódot, mert tartanak attól, hogy valamit elrontanak
C) Amikor a refaktorálás túl sokáig tart és blokkolja a feature fejlesztést
D) Amikor az IDE megakadályozza az automatikus refaktorálást
Helyes válasz: B
6. kérdés
Melyik állítás HAMIS a tesztekről?
A) A tesztek segítenek a regressziók felismerésében
B) 100%-os test coverage garantálja, hogy nincs bug a kódban
C) A tesztek dokumentációs mellékhatással is bírnak
D) A tesztek csökkentik a refaktorálástól való félelmet
Helyes válasz: B
7. kérdés
Az alábbi tesztnév közül melyik a leginkább dokumentáció-értékű?
A) test_1()
B) test_order()
C) test_discount_not_applied_when_price_is_zero()
D) test_apply_coupon_edge_case()
Helyes válasz: C
Magyarázat: A tesztnév pontosan leírja a szituációt és az elvárt viselkedést – ez a célja a teszt mint dokumentáció elvnek.
8. kérdés
Péter egy módosítást tesz az alkalmazásba, majd lefuttatja a meglévő teszteket. Minden teszt zöld. Melyik következtetés helyes?
A) A módosítás biztosan hibamentes
B) A módosítás nem rontott el semmit, amire volt teszt írva
C) A módosítás megfelel az összes üzleti követelménynek
D) A módosítás production-ready és deploy-olható
Helyes válasz: B
Magyarázat: A zöld tesztek csak azt garantálják, hogy a meglévő tesztek által lefedett esetek működnek. Ismeretlen hibák, lefedetlen esetek még benne lehetnek.
9. kérdés – Szituációs feladat
Anna egy számlázó rendszeren dolgozik. A calculate_vat() függvény kiszámolja az ÁFA összegét. Jelenleg ez a kód teszt nélkül van. Jövő héten fizetési módokat fog hozzáadni a rendszerhez.
Miért lenne hasznos, ha Anna most tesztet írna a calculate_vat() függvényre, mielőtt nekifog az új funkciónak?
(Nyílt kérdés – gondolkodj el a válaszon, mielőtt megnézed az útmutatót.)
Útmutató a jó válaszhoz:
- Ha a fizetési logika módosítja az összegszámítást (akár véletlenül), a teszt azonnal jelzi
- A teszt dokumentálja, hogyan viselkedik az ÁFA számítás most – ez referenciaként szolgál
- Refaktoráláshoz „biztosítékot" ad, ha az ÁFA logikát is érinteni kell az új feature során
10. kérdés – Igaz, hamis, vagy kontextustól függ?
Értékeld az alábbi állításokat! Minden állításhoz válaszd: Igaz, Hamis, vagy Kontextustól függ – és indokold röviden.
- „Minden kódsort tesztelni kell."
- „Ha a tesztek zöldek, deploy-olhatok production-ba."
- „A tesztek lassítják a fejlesztést."
- „Jobb teszt nélkül kiszállítani, mint késni a tesztírással."
Útmutató:
- Hamis – Triviális getter/setter, eldobandó prototype, generált kód esetén felesleges overhead.
- Kontextustól függ – Zöld tesztek szükséges, de nem elégséges feltétel. A tesztek minőségétől, lefedettségétől és a deploy folyamattól is függ.
- Kontextustól függ – Rövid távon igen, mert több idő kell. Hosszú távon csökkentik a debuggolásra és hotfix-ekre fordított időt.
- Kontextustól függ – Kritikus üzleti logikánál a teszt nélküli deploy komoly kockázat. Prototípusnál, MVP kísérletnél ez lehet elfogadható kompromisszum – de tudatos döntésnek kell lennie, nem lustaságból.