{"id":685,"date":"2026-06-11T00:35:56","date_gmt":"2026-06-10T23:35:56","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=685"},"modified":"2026-06-17T00:36:31","modified_gmt":"2026-06-16T23:36:31","slug":"archunit-architekturregeln-automatisch-als-unit-tests-pruefen","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=685","title":{"rendered":"ArchUnit \u2014 Architekturregeln automatisch als Unit-Tests pr\u00fcfen"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Architektur ist kein Zufall \u2014 aber sie l\u00e4sst sich schwer durchsetzen. Ein Entwickler f\u00fcgt eine Abh\u00e4ngigkeit zwischen zwei Modulen hinzu, die eigentlich getrennt bleiben sollten. Ein anderer benennt eine Controller-Klasse ohne das Suffix&nbsp;<code>Controller<\/code>. Solche Verst\u00f6\u00dfe fallen in Code-Reviews oft durch \u2014 aber nicht immer.&nbsp;<strong>ArchUnit<\/strong>&nbsp;macht Architekturregeln zu automatisch pr\u00fcfbaren Unit-Tests. Was mit JUnit Assertions f\u00fcr die Code-Logik funktioniert, leistet ArchUnit f\u00fcr die Code-Struktur.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Grundlagen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ArchUnit besteht aus zwei Komponenten:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>archunit<\/strong>\u00a0\u2014 die Kernbibliothek mit einer Fluent-API zum Definieren von Regeln<\/li>\n\n\n\n<li><strong>archunit-junit5<\/strong>\u00a0\u2014 Integration mit JUnit 5 f\u00fcr komfortables Testen<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>com.tngtech.archunit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>archunit-junit5<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>1.4.2<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">scope<\/span>&gt;<\/span>test<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">scope<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">ArchUnit analysiert den Java-Bytecode (keine Quelltextanalyse) und kann Regeln auf Package-, Klassen-, Methoden- und Feldebene definieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Paketabh\u00e4ngigkeiten \u00fcberwachen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Die h\u00e4ufigste Architekturregel betrifft Schichten und Paketabh\u00e4ngigkeiten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.junit<\/span><span class=\"hljs-selector-class\">.AnalyzeClasses<\/span>;\n<span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.junit<\/span><span class=\"hljs-selector-class\">.ArchTest<\/span>;\n<span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.lang<\/span><span class=\"hljs-selector-class\">.ArchRule<\/span>;\n\n<span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.Architectures<\/span><span class=\"hljs-selector-class\">.layeredArchitecture<\/span>;\n\n<span class=\"hljs-keyword\">@AnalyzeClasses<\/span>(packages = <span class=\"hljs-string\">\"com.example.shop\"<\/span>)\nclass SchichtenArchitekturTest {\n\n    <span class=\"hljs-keyword\">@ArchTest<\/span>\n    static final ArchRule schichtenRegel = layeredArchitecture()\n        .consideringAllDependencies()\n\n        .layer(<span class=\"hljs-string\">\"Controller\"<\/span>).definedBy(<span class=\"hljs-string\">\"..controller..\"<\/span>)\n        .layer(<span class=\"hljs-string\">\"Service\"<\/span>).definedBy(<span class=\"hljs-string\">\"..service..\"<\/span>)\n        .layer(<span class=\"hljs-string\">\"Repository\"<\/span>).definedBy(<span class=\"hljs-string\">\"..repository..\"<\/span>)\n        .layer(<span class=\"hljs-string\">\"Domain\"<\/span>).definedBy(<span class=\"hljs-string\">\"..domain..\"<\/span>)\n\n        .whereLayer(<span class=\"hljs-string\">\"Controller\"<\/span>).mayNotBeAccessedByAnyLayer()\n        .whereLayer(<span class=\"hljs-string\">\"Service\"<\/span>).mayOnlyBeAccessedByLayers(<span class=\"hljs-string\">\"Controller\"<\/span>)\n        .whereLayer(<span class=\"hljs-string\">\"Repository\"<\/span>).mayOnlyBeAccessedByLayers(<span class=\"hljs-string\">\"Service\"<\/span>)\n        .whereLayer(<span class=\"hljs-string\">\"Domain\"<\/span>).mayOnlyBeAccessedByLayers(<span class=\"hljs-string\">\"Service\"<\/span>, <span class=\"hljs-string\">\"Repository\"<\/span>);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Dieser Test schl\u00e4gt fehl, sobald ein Controller direkt auf ein Repository zugreift oder die Dom\u00e4nenschicht einen Service importiert \u2014 ein klassischer Fall von Architekturerosion.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Zyklenfreiheit erzwingen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Zirkul\u00e4re Abh\u00e4ngigkeiten zwischen Paketen sind ein Warnsignal f\u00fcr schlechte Modularisierung:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.dependencies<\/span><span class=\"hljs-selector-class\">.SlicesRuleDefinition<\/span><span class=\"hljs-selector-class\">.slices<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keineZyklen = slices()\n    .matching(<span class=\"hljs-string\">\"com.example.shop.(*)..\"<\/span>)\n    .should().beFreeOfCycles();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Ein Zyklus zwischen&nbsp;<code>com.example.shop.bestellung<\/code>&nbsp;und&nbsp;<code>com.example.shop.kunde<\/code>&nbsp;f\u00fchrt sofort zu einem roten Test.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Namenskonventionen durchsetzen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mit ArchUnit lassen sich auch Benennungsregeln zentral definieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.lang<\/span><span class=\"hljs-selector-class\">.syntax<\/span><span class=\"hljs-selector-class\">.ArchRuleDefinition<\/span><span class=\"hljs-selector-class\">.classes<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule controllerNamen = classes()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..controller..\"<\/span>)\n    .should().haveSimpleNameEndingWith(<span class=\"hljs-string\">\"Controller\"<\/span>);\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule serviceImplementierungen = classes()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..service..\"<\/span>)\n    .should().haveSimpleNameEndingWith(<span class=\"hljs-string\">\"Service\"<\/span>)\n    .andShould().beAnnotatedWith(Service.class);\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule repositoriesAlsInterfaces = classes()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..repository..\"<\/span>)\n    .should().beInterfaces();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Vertippt sich jemand und nennt einen Service&nbsp;<code>KundeVerwaltung<\/code>&nbsp;statt&nbsp;<code>KundeVerwaltungService<\/code>, signalisiert der ArchUnit-Test den Versto\u00df.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gesch\u00fctzte Zugriffe auf externe Bibliotheken<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Manche Klassen sollten bestimmte externe APIs nicht nutzen d\u00fcrfen. ArchUnit kann das pr\u00fcfen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.lang<\/span><span class=\"hljs-selector-class\">.syntax<\/span><span class=\"hljs-selector-class\">.ArchRuleDefinition<\/span><span class=\"hljs-selector-class\">.noClasses<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule serviceKeinSystemOut = noClasses()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..service..\"<\/span>)\n    .should().accessClassesThat()\n    .resideInAnyPackage(<span class=\"hljs-string\">\"java.util.logging..\"<\/span>, <span class=\"hljs-string\">\"java.sql..\"<\/span>);\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule domainKeineFrameworkAbh\u00e4ngigkeit = noClasses()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..domain..\"<\/span>)\n    .should().dependOnClassesThat()\n    .resideInAnyPackage(\n        <span class=\"hljs-string\">\"org.springframework..\"<\/span>,\n        <span class=\"hljs-string\">\"jakarta.persistence..\"<\/span>,\n        <span class=\"hljs-string\">\"com.fasterxml..\"<\/span>\n    );\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die Dom\u00e4nenschicht bleibt so frei von technischen Abh\u00e4ngigkeiten \u2014 ein Kernprinzip von Clean Architecture und Domain-Driven Design.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kapselung von Feldern<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Auch innerhalb von Klassen lassen sich Regeln definieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.lang<\/span><span class=\"hljs-selector-class\">.syntax<\/span><span class=\"hljs-selector-class\">.ArchRuleDefinition<\/span><span class=\"hljs-selector-class\">.fields<\/span>;\n<span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.lang<\/span><span class=\"hljs-selector-class\">.syntax<\/span><span class=\"hljs-selector-class\">.ArchRuleDefinition<\/span><span class=\"hljs-selector-class\">.noClasses<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keinePublicFelder = fields()\n    .that().areDeclaredInClassesThat()\n    .resideInAPackage(<span class=\"hljs-string\">\"..domain..\"<\/span>)\n    .should().bePrivate();\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keineJpaInDom\u00e4ne = noClasses()\n    .that().resideInAPackage(<span class=\"hljs-string\">\"..domain..\"<\/span>)\n    .should().accessClassesThat()\n    .resideInAnyPackage(<span class=\"hljs-string\">\"jakarta.persistence..\"<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">PlantUML-Integration: Diagramm als Regel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Eine Architektur kann auch als PlantUML-Komponentendiagramm modelliert und direkt als Regel eingebunden werden:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.plantuml<\/span><span class=\"hljs-selector-class\">.PlantUmlArchCondition<\/span>;\n\n<span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.plantuml<\/span><span class=\"hljs-selector-class\">.PlantUmlArchCondition<\/span><span class=\"hljs-selector-class\">.consideringOnlyDependenciesInAnyPackage<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule plantUmlRegel = PlantUmlArchCondition\n    .adhereToPlantUmlDiagram(\n        MyArchitectureTest.class.getResource(<span class=\"hljs-string\">\"\/architektur.puml\"<\/span>),\n        consideringOnlyDependenciesInAnyPackage(<span class=\"hljs-string\">\"com.example.shop..\"<\/span>));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">ArchUnit vergleicht dann die tats\u00e4chlichen Abh\u00e4ngigkeiten mit den im Diagramm erlaubten Verbindungen. So bleibt die Dokumentation im Code automatisch synchron mit der Realit\u00e4t.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Onion Architecture &amp; Hexagonal Architecture<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Neben der klassischen Schichtenarchitektur unterst\u00fctzt ArchUnit auch&nbsp;<strong>Onion Architecture<\/strong>&nbsp;(Hexagonal Architecture \/ Ports &amp; Adapters):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.Architectures<\/span><span class=\"hljs-selector-class\">.onionArchitecture<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule onionRegel = onionArchitecture()\n    .domainModels(<span class=\"hljs-string\">\"..domain.model..\"<\/span>)\n    .domainServices(<span class=\"hljs-string\">\"..domain.service..\"<\/span>)\n    .applicationServices(<span class=\"hljs-string\">\"..application..\"<\/span>)\n    .adapter(<span class=\"hljs-string\">\"rest\"<\/span>, <span class=\"hljs-string\">\"..adapter.rest..\"<\/span>)\n    .adapter(<span class=\"hljs-string\">\"persistence\"<\/span>, <span class=\"hljs-string\">\"..adapter.persistence..\"<\/span>);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die Dom\u00e4nenschicht ist der Kern und darf keine Abh\u00e4ngigkeiten nach au\u00dfen haben. Adapter d\u00fcrfen auf Dom\u00e4ne und Applikation zugreifen, aber nicht untereinander \u2014 ArchUnit pr\u00fcft diese Regeln automatisch.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">General Coding Rules<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr projekt\u00fcbergreifende Best Practices bietet ArchUnit vordefinierte&nbsp;<code>GeneralCodingRules<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">static<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.GeneralCodingRules<\/span>.*;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keinFieldInjection = NO_CLASSES_SHOULD_USE_FIELD_INJECTION;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keinSystemOut = NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keineGenericExceptions = NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule keineAltenDatumsklassen = OLD_DATE_AND_TIME_CLASSES_SHOULD_NOT_BE_USED;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Diese Regeln sind sofort einsetzbar und decken h\u00e4ufige Fallstricke wie Field Injection,&nbsp;<code>System.out<\/code>-Logging oder die Nutzung von&nbsp;<code>java.util.Date<\/code>&nbsp;ab.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Frozen Rules<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Hat man eine bestehende Codebasis mit vielen Architektur-Verst\u00f6\u00dfen, ist es unrealistisch, alle auf einmal zu beheben.&nbsp;<strong>Frozen Rules<\/strong>&nbsp;frieren den aktuellen Stand ein und schlagen nur bei neuen Verst\u00f6\u00dfen Alarm:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">com<\/span><span class=\"hljs-selector-class\">.tngtech<\/span><span class=\"hljs-selector-class\">.archunit<\/span><span class=\"hljs-selector-class\">.library<\/span><span class=\"hljs-selector-class\">.freeze<\/span><span class=\"hljs-selector-class\">.FreezingArchRule<\/span>;\n\n<span class=\"hljs-keyword\">@ArchTest<\/span>\nstatic final ArchRule schichtenRegel = FreezingArchRule\n    .freeze(layeredArchitecture()\n        .layer(<span class=\"hljs-string\">\"Controller\"<\/span>).definedBy(<span class=\"hljs-string\">\"..controller..\"<\/span>)\n        .layer(<span class=\"hljs-string\">\"Service\"<\/span>).definedBy(<span class=\"hljs-string\">\"..service..\"<\/span>)\n        .whereLayer(<span class=\"hljs-string\">\"Controller\"<\/span>).mayNotBeAccessedByAnyLayer()\n        .whereLayer(<span class=\"hljs-string\">\"Service\"<\/span>).mayOnlyBeAccessedByLayers(<span class=\"hljs-string\">\"Controller\"<\/span>));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Beim ersten Ausf\u00fchren speichert ArchUnit alle aktuellen Verst\u00f6\u00dfe in einem&nbsp;<code>ViolationStore<\/code>. Zuk\u00fcnftige Testl\u00e4ufe melden dann nur noch&nbsp;<strong>neue<\/strong>&nbsp;Verst\u00f6\u00dfe \u2014 bestehende werden toleriert. Um den aktuellen Stand aller Verst\u00f6\u00dfe bewusst neu einzufrieren, kann die Eigenschaft&nbsp;<code>freeze.refreeze<\/code>&nbsp;auf&nbsp;<code>true<\/code>&nbsp;gesetzt werden (z.\u202fB. via System-Property&nbsp;<code>-Darchunit.freeze.refreeze=true<\/code>). Der&nbsp;<code>ViolationStore<\/code>&nbsp;wird eingecheckt, sodass das gesamte Team dieselbe Baseline nutzt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ArchUnit verwandelt Architektur von einer subjektiven Diskussion in eine objektive, automatisierte Pr\u00fcfung. Es ersetzt kein Architekturverst\u00e4ndnis, macht aber Architekturregeln messbar und durchsetzbar. In CI\/CD-Pipelines sichern diese Tests die strukturelle Integrit\u00e4t des Codes bei jedem Commit \u2014 und das mit einer API, die jedem JUnit-Entwickler sofort vertraut ist.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Architektur ist kein Zufall \u2014 aber sie l\u00e4sst sich schwer durchsetzen. Ein Entwickler f\u00fcgt eine Abh\u00e4ngigkeit zwischen zwei Modulen hinzu, die eigentlich getrennt bleiben sollten. Ein anderer benennt eine Controller-Klasse ohne das Suffix&nbsp;Controller. Solche Verst\u00f6\u00dfe fallen in Code-Reviews oft durch \u2014 aber nicht immer.&nbsp;ArchUnit&nbsp;macht Architekturregeln zu automatisch pr\u00fcfbaren Unit-Tests. Was mit JUnit Assertions f\u00fcr die [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-685","post","type-post","status-publish","format-standard","hentry","category-plain_java"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/685","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=685"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/685\/revisions"}],"predecessor-version":[{"id":686,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/685\/revisions\/686"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}