Az ArchUnit bemutatása
1. Áttekintés
Ebben a cikkben bemutatjuk, hogyan ellenőrizhető a rendszer architektúrája ArchUnit.
2. Mi az ArchUnit?
Az architektúra tulajdonságai és a karbantarthatóság közötti kapcsolat jól tanulmányozott téma a szoftveriparban. A rendszereink hangrendszerének meghatározása azonban nem elég. Ellenőriznünk kell, hogy a bevezetett kód betartja-e azt.
Egyszerűen fogalmazva, ArchUnit egy tesztkönyvtár, amely lehetővé teszi számunkra, hogy ellenőrizzük, hogy egy alkalmazás betartja-e az adott építészeti szabályok halmazát. De mi az építészeti szabály? Sőt, mit is értünk ez alatt építészet ebben az összefüggésben?
Kezdjük az utóbbival. Itt használjuk a kifejezést építészet hivatkozniahogyan az alkalmazásunk különböző osztályait csomagokba rendezzük.
A rendszer architektúrája azt is meghatározza, hogy a csomagok vagy csomagcsoportok - más néven - hogyan rétegek - kölcsönhatásba lépni. Gyakorlati szempontból meghatározza, hogy az adott csomagban lévő kód meghívhatja-e a másikhoz tartozó osztály metódusát. Tegyük fel például, hogy alkalmazásunk architektúrája három réteget tartalmaz: bemutatás, szolgáltatás, és kitartás.
Az egyik módszer a rétegek kölcsönhatásának vizualizálására egy UML csomagdiagram és egy, az egyes rétegeket ábrázoló csomag segítségével:
Csak ezt a diagramot megnézve kitalálhatunk néhány szabályt:
- A bemutató óráknak csak a szolgáltatási osztályoktól kell függeniük
- A szolgáltatási osztályoknak csak a tartóssági osztályoktól kell függeniük
- A perzisztencia osztályok nem függhetnek senkitől
Ezeket a szabályokat megvizsgálva most visszatérhetünk és megválaszolhatjuk eredeti kérdésünket. Ebben az összefüggésben egy építészeti szabály állítás arról, hogy alkalmazásosztályaink hogyan hatnak egymásra.
Tehát most hogyan ellenőrizhetjük, hogy megvalósításunk betartja-e ezeket a szabályokat? Itt van, ahol ArchUnit bejön. Ez lehetővé teszi számunkra, hogy az a segítségével kifejezzük építészeti kényszereinket folyékony API és validálja őket más tesztekkel együtt egy rendszeres felépítés során.
3. ArchUnit Projekt beállítása
ArchUnit szépen integrálódik a JUnit teszt keretrendszer, és így általában együtt használják őket. Csak annyit kell tennünk, hogy hozzáadjuk a archunit-junit4 függőség, hogy megfeleljen a mi JUnit változat:
com.tngtech.archunit archunit-junit4 0.14.1 teszt
Mint annak artefactId azt jelenti, hogy ez a függőség a JUnit 4 keret.
Van még egy archunit-junit5 függőség, ha használjuk JUnit 5:
com.tngtech.archunit archunit-junit5 0.14.1 teszt
4. Írás ArchUnit Tesztek
Miután hozzáadtuk a megfelelő függőséget a projektünkhöz, kezdjük el írni az architektúra tesztjeinket. Tesztalkalmazásunk egy egyszerű SpringBoot REST alkalmazás lesz, amely lekérdezi a Törpöket. Az egyszerűség kedvéért ez a tesztalkalmazás csak a Vezérlő, Szolgáltatás, és Adattár osztályok.
Szeretnénk ellenőrizni, hogy ez az alkalmazás megfelel-e az előbb említett szabályoknak. Tehát kezdjük a „prezentációs osztályok csak a szolgáltatási osztályoktól függnek” szabály egyszerű tesztjével.
4.1. Első tesztünk
Az első lépés egy olyan Java osztály létrehozása, amely ellenőrzi a szabályok megsértését. Ezt úgy tesszük, hogy a ClassFileImporter osztály, majd annak egyikét használjuk importXXX () mód:
JavaClasses jc = new ClassFileImporter () .importPackages ("com.baeldung.archunit.smurfs");
Ebben az esetben a JavaClasses példány tartalmazza az összes osztályt a fő alkalmazáscsomagunkból és annak alcsomagjaiból. Úgy gondolhatjuk, hogy ez az objektum analóg egy tipikus tesztalanyra, amelyet a rendszeres egységvizsgálatok során használnak, mivel ez lesz a szabályértékelések célpontja.
Az építészeti szabályok az egyik statikus módszert használják ArchRuleDefinition osztály kiindulópontja annak folyékony API hívások. Próbáljuk meg végrehajtani az első fent definiált szabályt ennek az API-nak a használatával. Használjuk a osztályok () metódust, és adjunk hozzá további korlátozásokat onnan:
ArchRule r1 = class () .that (). ResideInAPackage (".. prezentáció ..") .should (). OnlyDependOnClassesThat () .resideInAPackage (".. service .."); r1.ellenőrzés (jc);
Figyelje meg, hogy felhívnunk kell a jelölje be() az ellenőrzés futtatásához létrehozott szabály metódusa. Ez a módszer a JavaClasses objektumot és kivételt vet, ha megsértik.
Mindez jól néz ki, de kapunk egy listát a hibákról, ha megpróbáljuk futtatni a kódunkkal:
java.lang.AssertionError: Architektúra megsértése [Prioritás: KÖZEPES] - A „..presentation ..” csomagban található „osztály” osztályok csak azoktól az osztályoktól függhetnek, amelyek a „..service ..” csomagban találhatók ( 6 alkalommal): ... a hibalista kihagyva
Miért? Ennek a szabálynak a fő problémája a onlyDependsOnClassesThat (). Annak ellenére, hogy mit tettünk a csomag diagramba, tényleges megvalósításunk függ a JVM és a Spring keretosztályoktól, ezért a hiba.
4.2. Az első tesztünk átírása
A hiba megoldásának egyik módja egy olyan záradék hozzáadása, amely figyelembe veszi ezeket a további függőségeket:
ArchRule r1 = class () .that (). ResideInAPackage (".. prezentáció ..") .should (). OnlyDependOnClassesThat () .resideInAPackage (".. service ..", "java ..", "javax .. "," org.springframework .. ");
Ezzel a változtatással az ellenőrzésünk nem fog sikerülni. Ez a megközelítés azonban fenntarthatósági problémákkal küzd és kissé hackernek érzi magát. Kerülhetjük azokat a kérdéseket, amelyek a szabály használatával írják át a szabályunkat noClasses () statikus módszer kiindulópontként:
ArchRule r1 = noClasses () .that (). ResideInAPackage (".. prezentáció ..") .should (). DependOnClassesThat () .resideInAPackage (".. kitartás ..");
Természetesen rámutathatunk arra is, hogy ez a megközelítés az tagadás alapú a helyett engedély-alapú az egyik, ami korábban volt. A kritikus pont az, hogy bármilyen megközelítést választunk, ArchUnit általában elég rugalmas lesz a szabályaink kifejezéséhez.
5. A KönyvtárAPI
ArchUnit a bonyolult építészeti szabályok létrehozását a beépített szabályainak köszönhetően könnyű feladattá teszi. Ezek viszont szintén kombinálhatók, lehetővé téve számunkra az absztrakció magasabb szintjét használó szabályok létrehozását. A dobozból, ArchUnit felajánlja a Library API, előre csomagolt szabályok gyűjteménye, amelyek foglalkoznak a közös architektúra aggályaival:
- Építészet: Réteges és hagymás (más néven hatszögletű vagy „portok és adapterek”) architektúrák támogatása
- Szeletek: Körkörös függőségek vagy „ciklusok” detektálására szolgál
- Tábornok: A legjobb kódolási gyakorlatokkal kapcsolatos szabályok gyűjtése, például naplózás, kivételek használata stb.
- PlantUML: Ellenőrzi, hogy a kódbázisunk megfelel-e egy adott UML modellnek
- Freeze Arch szabályok: Mentse el a szabálysértéseket későbbi használatra, lehetővé téve csak újak bejelentését. Különösen hasznos a technikai adósságok kezelésében
Ezeknek a szabályoknak a lefedése nem tartozik a bevezetés hatálya alá, de nézzük meg a Építészet szabálycsomag. Írjuk át különösen az előző szakaszban szereplő szabályokat a réteges architektúra szabályok használatával. Ezeknek a szabályoknak a használata két lépést igényel: először meghatározzuk alkalmazásunk rétegeit. Ezután meghatározzuk, hogy melyik réteghez való hozzáférés engedélyezett:
LayeredArchitecture arch = layeredArchitecture () // Definiálja a rétegeket .layer ("Presentation"). DefineBy (".. prezentáció ..") .layer ("Service"). DefineBy (".. service ..") .layer (" Perzisztencia "). DefineBy (" .. perzisztencia .. ") // Korlátok hozzáadása .whereLayer (" Prezentáció "). MayNotBeAccessedByAnyLayer () .whereLayer (" Szolgáltatás "). MayOnlyBeAccessedByLayers (" Bemutatás ") .whereLayer (" Perzisztencia ") .mayOnlyBeAccessedByLayers ("Szolgáltatás"); arch.check (jc);
Itt, réteges építészet () egy statikus módszer a Építészet osztály. Meghívásakor új értéket ad vissza Réteges építészet objektum, amelyet ezután használunk a névrétegek és állítások meghatározására a függőségükkel kapcsolatban. Ez az objektum valósítja meg a ArchRule felületet, hogy ugyanúgy használhassuk, mint bármely más szabályt.
Az a jó dolog ebben a bizonyos API-ban, hogy lehetővé teszi számunkra, hogy néhány kódsorban hozzunk létre olyan szabályokat, amelyek egyébként több egyedi szabály kombinálását igényelnék.
6. Következtetés
Ebben a cikkben a használat alapjait tártuk fel ArchUnit projektjeinkben. Ennek az eszköznek az alkalmazása egy viszonylag egyszerű feladat, amely pozitív hatással lehet az általános minőségre és hosszú távon csökkentheti a karbantartási költségeket.
Szokás szerint az összes kód elérhető a GitHubon.