Regresszió — olyan hiba, amely a kód módosítása után jelenik meg, annak ellenére, hogy ugyanaz a funkció korábban helyesen működött. A regresszió azt jelenti, hogy az új változtatás „eltörte“ azt, ami korábban már meg volt írva és tesztelve. Ez az egyik leggyakoribb és legveszélyesebb probléma a fejlesztésben: egy hiba javítása közben a fejlesztő észrevétlenül eltörhet három másik funkciót. A Capers Jones Software Engineering 2023 szerint a regressziós hibák átlagos sűrűsége 1–3 minden 100 módosított kódsorra vetítve. Áttekintjük a regressziók okait, felderítési módszereit és megelőzési stratégiáit.
Főbb pontok
Regresszió — olyan helyzet, amikor egy korábbi verzióban működő funkció a változtatások után leáll. A változtatás bármi lehet: hibajavítás, új funkció hozzáadása, refaktorálás, könyvtár frissítése vagy akár konfiguráció módosítása. A regresszió a stabilitás fő ellensége: minden változtatás kockáztatja, hogy eltör valamit, ami már ellenőrzésre került és kiadásra került.
A kifejezés a tesztelésből származik: regressziós tesztelés — a meglévő tesztek újrafuttatása minden változtatás után. Ha egy korábban sikeres teszt megbukik — regresszió történt. Tágabb értelemben a regresszió nemcsak a teszt bukása, hanem a felhasználó vagy QA által észlelt viselkedésromlás is. A Tricentis State of Testing 2023 szerint a regressziók az élesben talált hibák 35–45%-át teszik ki.
A regresszió a közönséges hibától időbeli kontextusban különbözik: a hiba mindig is létezhetett, míg a regresszió mindig egy változtatás eredménye. Ez fontos különbség, mert a regresszió okának keresése a változtatások elemzésével kezdődik: mi változott a „működött“ és a „leállt“ között. Git bisect — a regressziót okozó commit megtalálásának szabványos eszköze.
Helyi regresszió — az A modulban végzett változtatás ugyanabban az A modulban rontja el a funkciót. Példa: a fejlesztő újraírja a rendező függvényt, és az nem dolgozza fel megfelelően az üres tömböt. A helyi regressziót a legkönnyebb felderíteni és javítani, mert az ok és az okozat közel van egymáshoz.
Távoli regresszió — az A modulban végzett változtatás a B modulban rontja el a funkciót, amely nem közvetlenül kód által, hanem adatok vagy idő által kapcsolódik. Példa: az adatbázis séma módosítása a „Felhasználók“ modulban elront egy jelentést az „Analitika“ modulban, amely ugyanazt a táblát használja. A távoli regressziók a legveszélyesebbek: a fejlesztő nem gyanítja, hogy változtatása egy másik modult érint.
Mellékhatás regresszió — egy mellékhatás (naplózás, gyorsítótárazás, értesítésküldés) módosítása elrontja a várt viselkedést. Példa: a fejlesztő gyorsítótárazást adott hozzá a munka felgyorsításához, de az elavult gyorsítótár miatt a felhasználók régi adatokat látnak. A mellékhatás regressziókat nehéz automatikus tesztekkel elkapni, mert a mellékhatások gyakran nincsenek tesztelve.
Teljesítményregresszió — a kód funkcionálisan továbbra is helyesen működik, de lassabban, mint korábban. Példa: az új titkosítási algoritmus ugyanazokat az eredményeket adja, de a végrehajtási idő 2 ms-ról 200 ms-ra nőtt. A teljesítményregressziókat a szokásos egységtesztek nem érzékelik — benchmarkokra és profilozásra van szükség.
| Regresszió típusa | Példa | Felderítési mód |
|---|---|---|
| Helyi | Eltört rendezés | Egységtesztek |
| Távoli | Adatbázis séma módosítás | Integrációs tesztek |
| Mellékhatás | Elavult gyorsítótár | E2E tesztek |
| Teljesítmény | Válasz lelassulása | Benchmarkok |
Első ok — kódösszefonódás (coupling). Minél erősebben függnek a modulok egymástól, annál nagyobb a valószínűsége, hogy az egyikben történt változtatás regressziót okoz a másikban. Klasszikus antiminták: God Object (objektum, ami mindent csinál), Shotgun Surgery (egy módosítása tucatnyi helyen igényel javítást), Circular Dependency. A coupling csökkentése — az architektúra feladata: SOLID elvek, Dependency Injection, hexagonális architektúra.
Második ok — tesztek hiánya a módosított funkcióhoz. Ha a kód nincs tesztelve, a fejlesztő csak a QA-tól vagy a felhasználóktól értesül a regresszióról. A Google Testing Blog szerint a >75%-os tesztlefedettségű projektekben 5-ször kevesebb regresszió van, mint a <25%-os lefedettségűekben. A TDD (Test-Driven Development) garantálja, hogy a tesztek a kód előtt íródnak, nem „ha lesz idő“.
Harmadik ok — emberi tényező. A fejlesztő nem tud a szomszédos funkció létezéséről, nem érti az összes függőséget, vagy egyszerűen siet. Ok — elégtelen tudásmegosztás a kódbázisról. Megoldások: code review más modulok fejlesztőinek részvételével, pair programming, architektúra dokumentálása. A projekt Bus faktora fordítottan arányos a dokumentált architektúrális döntések számával.
Regressziós tesztelés — a meglévő tesztek újrafuttatásának folyamata minden változtatás után annak ellenőrzésére, hogy a régi funkció nem tört el. Ez az egyetlen módja annak, hogy garantáljuk: az új változtatás nem zavarta meg a meglévő kód működését. Regressziós tesztelés nélkül minden kiadás lottó: a fejlesztő reméli, hogy nem tört el semmit, de nem tudja megerősíteni.
A kézi regressziós tesztelés — a legdrágább és leghatástalanabb megközelítés. A projekt növekedésével a regressziós tesztforgatókönyvek száma lineárisan, a kézi végrehajtás ideje pedig exponenciálisan nő. 2–3 év fejlesztés után a regresszió kézi végrehajtása 2–3 hétig is tarthat, ami lehetetlenné teszi a gyakori kiadásokat. Az egyetlen kiút az automatizálás.
Automatizált regressziós tesztelés szintekre oszlik a tesztpiramis szerint:
A Google Testing Blog szerint az optimális arány: 70% egységteszt, 20% integrációs, 10% E2E. Az ettől való eltérés csökkenti a regressziós tesztelés hatékonyságát: a túl sok E2E teszt lassítja a pipeline-t, az egységtesztek hiánya észrevétlenül hagyja a mikrohibákat.
Első stratégia — Full Regression. A projekt összes tesztje lefut. A legmegbízhatóbb, de a leglassabb megközelítés. Kisebb projekteknél alkalmazható (10 000 tesztig, futási idő <30 perc). Nagy projekteknél a teljes regresszió órákig tarthat, ami a CI/CD pipeline-t praktikátlanná teszi.
Második stratégia — Selective Regression. Csak a módosított kódhoz kapcsolódó tesztek futnak le. A kapcsolatok meghatározásához a kód függőségi gráfját használják. Eszközök: Bazel (Google), Nx (JavaScript), sbt (Scala). A Selective regression 60–80% futási időt takarít meg, de a függőségi gráf pontos felépítését igényli — a hibák kihagyott regressziókhoz vezetnek.
Harmadik stratégia — Prioritized Regression. Minden teszt prioritás szerint van rangsorolva: critical path (legfontosabb felhasználói forgatókönyvek), high risk (hibaelőzménnyel rendelkező kód), changed code (változtatás által érintett kód). Először a legmagasabb prioritású tesztek futnak le — ha sikeresek, a fejlesztő gyors visszajelzést kap. Időkorlátos futtatás: 10 percen belül a kritikus tesztek ellenőrzésre kerülnek, a többi — a háttérben.
Az első és legfontosabb lépés — a tesztírás kultúrája. Minden változtatást kísérjen egy teszt, amely ellenőrzi, hogy a változtatás működik, és egy teszt, amely ellenőrzi, hogy semmi nem tört el. A TDD (Test-Driven Development) adja a legjobb eredményeket: a fejlesztő először megírja a bukó tesztet, majd a kódot, amely sikeresen teljesíti azt. Ez garantálja, hogy a teszt a kód előtt létezik.
Második lépés — CI/CD pipeline kötelező tesztfuttatással. A pull request nem egyesíthető, amíg az összes teszt nem sikeres. A tesztek nem “ugorhatók át” sürgősség miatt — a sürgős változtatások egy gyorsított, de kötelező tesztszettemen mennek keresztül. A Google DevOps Research szerint a kötelező CI/CD-vel rendelkező csapatok 3-szor kevesebb regressziót tapasztalnak élesben.
Harmadik lépés — monitorozás élesben. Még a legjobb tesztek sem garantálnak 100% védelmet a regressziók ellen. Az observability eszközök (Sentry, Datadog, New Relic) minden telepítés után kövessék a kulcs metrikákat: hibaszázalék, késleltetés, átbocsátóképesség. Automatikus visszaállítás (rollback) a küszöbértékek túllépése esetén — biztonsági háló, ha a regresszió mégis élesbe kerül.
Negyedik lépés — code review regressziós gondolkodással. A bírálónak fel kell tennie a kérdést: “Mely más modulok törhetnek el ettől a változtatástól?”. Nem elég ellenőrizni, hogy a kód helyes — ellenőrizni kell, hogy nem zavarja-e a szomszédos funkciót. A code review ellenőrzőlistának tartalmaznia kell a “regressziók ellenőrzése a szomszédos modulokban” pontot.
Gyakran Ismételt Kérdések
A regresszió — olyan hiba, amely korábban nem létezett. A közönséges hiba a funkció létrehozásától fogva is létezhetett. A regresszió mindig egy konkrét változtatáshoz kötődik — ez lehetővé teszi a git bisect használatát az ok megtalálásához.
Használja a git bisect-et: adja meg a commit-ot, ahol minden működött, és a commit-ot, ahol elromlott. A Git bináris keresést végez a történetben, és megtalálja a regressziót okozó commit-ot. Ez még a több ezer commit-tal rendelkező nagy projekteknél is működik.
Nincs pontos szám, de van egy empirikus szabály: a kulcsfontosságú felhasználói folyamatok lefedettsége 100% legyen, az összes funkció lefedettsége legalább 70%. A minőség fontosabb, mint a mennyiség: egy edge case-t ellenőrző teszt értékesebb, mint tíz teszt a happy path-en.
Igen, és ezt infrastructure regression-nek hívják. Az operációs rendszer, az adatbázis verzió, az SSL-tanúsítvány vagy a webkiszolgáló konfiguráció frissítése eltörheti a működő kódot. Az IaC (Infrastructure as Code) és az infrastruktúra tesztelés (Test Kitchen, Terratest) segít az ilyen regressziók elkapásában.
Kezdje egy kritikus felhasználói folyamattal. Írjon automatikus tesztet a legfontosabb forgatókönyvhöz (bejelentkezés, rendelés leadás). Mutassa be demón, hogyan kapja el a teszt a regressziót. Amikor a csapat látja az előnyt — vezesse be a tesztelést fokozatosan, bővítve a lefedettséget.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is