Files
fete/backend/src/test/java/de/fete/HexagonalArchitectureTest.java
T
nitrix d333ab3d39
CI / backend-test (push) Successful in 1m1s
CI / frontend-test (push) Successful in 26s
CI / frontend-e2e (push) Successful in 1m25s
CI / build-and-publish (push) Has been skipped
Refactor domain models to records and move exceptions to sub-package
- Convert Event and Rsvp from mutable POJOs to Java records
- Move all 8 exception classes to application.service.exception sub-package
- Add ArchUnit rule enforcing domain models must be records

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:09:27 +01:00

93 lines
3.6 KiB
Java

package de.fete;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import static com.tngtech.archunit.library.Architectures.onionArchitecture;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
@AnalyzeClasses(packages = "de.fete", importOptions = ImportOption.DoNotIncludeTests.class)
class HexagonalArchitectureTest {
@ArchTest
static final ArchRule onionArchitectureIsRespected = onionArchitecture()
.domainModels("de.fete.domain.model..")
.domainServices("de.fete.domain.port.in..", "de.fete.domain.port.out..")
.applicationServices("de.fete.application.service..")
.adapter("web", "de.fete.adapter.in.web..")
.adapter("persistence", "de.fete.adapter.out.persistence..")
.adapter("config", "de.fete.config..");
@ArchTest
static final ArchRule domainMustNotDependOnAdapters = noClasses()
.that().resideInAPackage("de.fete.domain..")
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter..");
@ArchTest
static final ArchRule domainMustNotDependOnApplication = noClasses()
.that().resideInAPackage("de.fete.domain..")
.should().dependOnClassesThat().resideInAPackage("de.fete.application..");
@ArchTest
static final ArchRule domainMustNotDependOnConfig = noClasses()
.that().resideInAPackage("de.fete.domain..")
.should().dependOnClassesThat().resideInAPackage("de.fete.config..");
@ArchTest
static final ArchRule inboundPortsMustBeInterfaces = classes()
.that().resideInAPackage("de.fete.domain.port.in..")
.should().beInterfaces();
@ArchTest
static final ArchRule outboundPortsMustBeInterfaces = classes()
.that().resideInAPackage("de.fete.domain.port.out..")
.should().beInterfaces();
@ArchTest
static final ArchRule domainMustNotUseSpring = noClasses()
.that().resideInAPackage("de.fete.domain..")
.should().dependOnClassesThat().resideInAPackage("org.springframework..");
@ArchTest
static final ArchRule webMustNotDependOnPersistence = noClasses()
.that().resideInAPackage("de.fete.adapter.in.web..")
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter.out.persistence..");
@ArchTest
static final ArchRule persistenceMustNotDependOnWeb = noClasses()
.that().resideInAPackage("de.fete.adapter.out.persistence..")
.should().dependOnClassesThat().resideInAPackage("de.fete.adapter.in.web..");
@ArchTest
static final ArchRule webAdapterMustNotDependOnOutboundPorts = noClasses()
.that().resideInAPackage("de.fete.adapter.in.web..")
.should().dependOnClassesThat().resideInAPackage("de.fete.domain.port.out..");
@ArchTest
static final ArchRule domainModelsMustBeRecords = classes()
.that().resideInAPackage("de.fete.domain.model..")
.and().doNotHaveSimpleName("package-info")
.should(beRecords());
private static ArchCondition<JavaClass> beRecords() {
return new ArchCondition<>("be records") {
@Override
public void check(JavaClass javaClass,
ConditionEvents events) {
boolean isRecord = javaClass.reflect().isRecord();
if (!isRecord) {
events.add(SimpleConditionEvent.violated(javaClass,
javaClass.getFullName() + " is not a record"));
}
}
};
}
}