A router konfigurálása Angular alkalmazásokban kulcsfontosságú annak érdekében, hogy a felhasználók gördülékeny navigációt és dinamikusan töltődő funkciókat élvezhessenek. Az Angular lehetővé teszi a különböző útvonalak beállítását, és a "lazy loading" segítségével optimalizálhatjuk az alkalmazás betöltési sebességét, miközben biztosítjuk, hogy a felhasználói élmény zökkenőmentes maradjon. Az alábbiakban részletesen bemutatom, hogyan konfigurálhatjuk a routert különböző modulokkal és útvonalakkal, figyelembe véve az alkalmazásunk teljesítményét és skálázhatóságát.
Az egyik fontos alapelv az, hogy a különböző modulok között elérhető útvonalak nem mindig fognak egyesülni. Például, míg az alapvető útvonalakat, mint a rootRouter, gyakran közvetlenül betöltjük, addig a "lazy loaded" modulok csak akkor töltődnek be, amikor a felhasználó az adott útvonalat meglátogatja. Az útvonalakat különböző formátumokban, például kitöltött (eager loading) vagy késleltetett (lazy loading) módon konfigurálhatjuk. A loadChildren kulcsfontosságú szerepet játszik az ilyen típusú konfigurációkban, mivel lehetővé teszi, hogy egyes modulok dinamikusan töltődjenek be.
Vegyünk egy példát egy alapvető router konfigurációra a rootRouter-ban. Ebben az esetben az útvonalak között szerepel egy lazán betöltött modul, a BModule, amely a childRouter-en keresztül további alkatrészeket tartalmaz. A childRouter különböző útvonalakat definiál, amelyek nem találhatók meg a rootRouter-ben, mégis a navigáció során elérhetők. Ha az alkalmazásban a /b/a vagy /b/b útvonalra navigálunk, a rendszer automatikusan betölti a BModule-ot, miközben az alapvető alkalmazás, például az AComponent, az MasterComponent, és a DetailComponent előre betöltődnek.
A router konfigurációkban megjelenő path és component kulcsok segítenek meghatározni, hogy mely komponensek lesznek elérhetők a felhasználók számára. A példában az AComponent az alapértelmezett komponens, amely a /a útvonalhoz tartozik, míg a BModule-ban található BAComponent és BBComponent csak akkor töltődnek be, ha a felhasználó kifejezetten a /b/a vagy /b/b útvonalat választja.
A lazán betöltött modulok az Angular alkalmazás teljesítményének javítását szolgálják. Ahelyett, hogy az alkalmazás összes komponense egyszerre töltene be, a rendszer csak a szükséges modulokat tölti be, amikor azokra szükség van. Ez csökkenti az alkalmazás kezdeti betöltési idejét és erőforrást takarít meg, különösen nagy alkalmazások esetében.
Miután a szükséges komponensek és útvonalak beállítása megtörtént, a következő lépés az, hogy a modult késleltetett betöltésre állítjuk be. Az Angular DevTools segítségével nyomon követhetjük, hogyan történik a modulok betöltése, és megfigyelhetjük, hogy a megfelelő "chunking" hogyan segíti elő a gyorsabb alkalmazáskezelést. A loadChildren kulcs használatával az útvonalak dinamikusan, inline importálással vannak konfigurálva, ami biztosítja a típusbiztonságot anélkül, hogy az alkalmazás első betöltésekor minden modult egyszerre kellene betölteni.
Például, a ManagerModule beállítása esetén a következő módon érhetjük el, hogy a modul csak akkor töltődjön be, amikor a felhasználó a "manager" útvonalra navigál. A következő beállításokkal létrehozhatunk egy "lazy loading" modult:
A fenti konfigurációval biztosítjuk, hogy a ManagerModule csak akkor töltődjön be, amikor a felhasználó a "manager" útvonalra lép. A loadChildren tulajdonság a ManagerModule-ot egy inline importálással tölti be, ami lehetővé teszi, hogy az alkalmazás külön fájlba oszthassa szét a kódot, és a szükséges fájlokat csak akkor töltse le, amikor valóban szükség van rájuk.
Fontos megjegyezni, hogy a "lazy loading" nemcsak a teljes modulokra, hanem akár a különböző komponensekre is alkalmazható. A késleltetett betöltés olyan környezetekben lehet különösen hasznos, ahol az alkalmazás különböző funkciói különböző időpontokban kerülnek használatra, és így elkerülhetjük a szükségtelen kód letöltését a kezdeti alkalmazásbetöltés során.
A modulok és útvonalak konfigurálásakor az Angular rugalmasságot biztosít, így a fejlesztők a különböző alkalmazásstruktúrák és felhasználói igények alapján alakíthatják ki a router rendszert. A legfontosabb, hogy mindig figyelembe vegyük a felhasználói élményt, és optimalizáljuk az alkalmazás betöltési idejét, miközben biztosítjuk a gördülékeny navigációt.
Miért nem valóságosak az Angular unit tesztek?
A modern fejlesztési környezetekben, amelyek folyamatosan új kihívásokat és komplexitást hoznak, a hibák elkerülése és a minőségi kód biztosítása kulcsfontosságú. A fejlesztők napi szinten szembesülnek a különböző eszközökkel és módszerekkel, mint például a StackOverflow válaszok, blogposztok, npm csomagok vagy olyan nagy könyvtárak, mint az Angular. Az időszűkében és az ambíciók, valamint a nem jól megtervezett architektúrák hatására elkerülhetetlenek a hibák. Ilyen környezetben a tesztelés és a megfelelő automatizált tesztek létfontosságúak a kód minőségének fenntartásában.
Az Angular két fő tesztelési kategóriát kínál: az egységteszteket (unit tests) és az end-to-end (e2e) teszteket. Az egységtesztek gyorsan és könnyen létrehozhatók, míg az e2e tesztek lassabbak és költségesebbek. Azonban van egy alapvető probléma: az Angular egységtesztek nem valós egységtesztek. Miért is van ez így? A válasz megértéséhez mélyebb bepillantást kell nyernünk az egységtesztelés alapjaiba és annak elveibe, például a FIRST és SOLID elveibe.
Az egységtesztelés célja, hogy biztosítsa, hogy az alkalmazás viselkedése idővel ne változzon meg véletlenül. Az egységtesztek lehetővé teszik a fejlesztők számára, hogy folytassák az alkalmazás változtatását anélkül, hogy új hibákat hoznának be a már tesztelt funkciókba. Az egységtesztet úgy kell megírni, hogy kizárólag a tesztelt funkcióval (Function Under Test, FUT) vagy osztállyal (Class Under Test, CUT) foglalkozzon. Az ilyen tesztek gyorsak, automatizáltak és minden esetben könnyen futtathatók. Az egységteszteket a kóddal együtt kell írni, mivel ha azok el vannak választva a megvalósítástól, akár egy-két nap elteltével is elfelejthetjük a kód részleteit, és így a potenciális széljegyzeteket is.
Az egységteszteknek a FIRST elveinek kell megfelelniük:
-
Gyorsak: A tesztek millisekundumok alatt lefutnak, lehetővé téve, hogy akár több ezer teszt is futtatható legyen pár perc alatt.
-
Elkülönítettek: Az egységtesztnek nem szabad adatbázishoz csatlakoznia, hálózati kéréseket végeznie vagy a DOM-mal interakcióba lépnie.
-
Ismételhetőek: Mivel a tesztek teljesen izoláltak, minden futtatásuk ugyanazt az eredményt kell, hogy adja.
-
Önvizsgálóak: A tesztek helyes működése anélkül is igazolható, hogy külső környezetekre kellene támaszkodnunk.
-
Időben történőek: Az egységteszteket azonnal el kell készíteni a kód írásával párhuzamosan, különben elveszítjük az előnyeiket.
A tesztek gyorsasága érdekében az egységtesztek nem érhetik el a hálózati kéréseket vagy a DOM manipulációját. Ehhez a tesztelési eszközként úgynevezett tesztduplikátumokat (test doubles) használhatunk. A tesztduplikátumok lehetővé teszik számunkra a külső függőségek kontrollálását, így például egy hamis vagy mockolt HttpService-t injektálhatunk a komponensünkbe, nem pedig a valódi szolgáltatást. Ezáltal az egységtesztek gyorsak és ismételhetőek maradnak.
De mennyi tesztelés elegendő? Legalább annyi tesztet kell írni, mint ahány sor termelési kódot, különben nem végeztünk elég tesztelést. Az egységtesztek nem az egyetlen típusú tesztek, amiket létrehozhatunk, de minden bizonnyal azokat kell a legtöbb esetben alkalmaznunk. Az egység-, integrációs és UI tesztek három alapvető típus, amelyeket különböző célokra használhatunk. Az egységtesztek a leggyorsabbak, de az integrációs tesztek a különböző komponensek közötti interakciókat, például adatbázis-hívásokat, hálózati kéréseket és a DOM-mal való interakciót is tesztelik, ami miatt lassabbak és drágábbak, mint az egységtesztek. Az UI tesztek az alkalmazást a felhasználó szemszögéből vizsgálják, de az ilyen tesztek gyakran törékenyek, mivel az alkalmazás UI-ja gyakran változik.
Mike Cohn tesztelési piramisa jól szemlélteti, hogy az egyes tesztkategóriákat milyen arányban kell alkalmaznunk az alkalmazásunkban. A piramis alján találhatók az egységtesztek, amelyeknek nagy mennyiségben kell jelen lenniük, míg az integrációs és UI tesztek kevesebb számúak, mivel azok drágábbak és lassabbak.
Az Angular esetében a valódi unit tesztelés nem valósulhat meg. Az Angular komponens teszteléséhez szükséges TestBed, amely a DOM-mal való interakciót és a szolgáltatások injektálását is magában foglalja, valójában lassú és törékeny. Az Angular tesztek így nem felelnek meg az egységtesztelés alapvető szabályainak. A jövőben talán változnak az Angular tesztelési megoldásai, de addig is célszerű az üzleti logikát szolgáltatásokba és függvényekbe kivonni, amelyeket alaposan tesztelhetünk. A Cypress komponens tesztek és a Cypress end-to-end tesztek is segíthetnek az Angular alkalmazások tesztelésében, ha a cél az integrációs és UI tesztelés.
A tesztelési infrastruktúra folyamatos fejlődése, például a Cypress beállítása az e2e tesztekhez, a Web Test Runner bevezetése Angular 17.1 verzióban, és a Cypress-nek az Angular projektekhez történő integrálása mind olyan lépések, amelyek segíthetnek a fejlesztők számára a kód minőségének javításában és a tesztelési folyamatok egyszerűsítésében.
Milyen szerepet játszhatnak a sűrített levegős motorok a fenntartható közlekedés jövőjében?
Hogyan élik meg a háborút és a magányt a mindennapi életben?
Hogyan alakíthatjuk a vállalati növekedést: Az innováció és a kreativitás szerepe a piacon
Hogyan működik a rehabilitáció az addikciók kezelésében?

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский