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.