diff --git a/src/test/java/com/runtimematrix/architecture/LayerBoundaryTest.java b/src/test/java/com/runtimematrix/architecture/LayerBoundaryTest.java new file mode 100644 index 0000000..30e6a84 --- /dev/null +++ b/src/test/java/com/runtimematrix/architecture/LayerBoundaryTest.java @@ -0,0 +1,62 @@ +package com.runtimematrix.architecture; + +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.library.Architectures.layeredArchitecture; +import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static com.tngtech.archunit.library.DependencyRules.NO_CLASSES_DEPEND_ON_UPPER_LAYERS; + +/** ADR-001 레이어 경계 Arquillian 테스트 */ +@DisplayName("아키텍처 경계 검증") +class LayerBoundaryTest { + + private JavaClasses classes; + + @BeforeEach + void setUp() { + classes = new ClassFileImporter().importPackages("com.runtimematrix"); + } + + @Test + @DisplayName("Controller는 Service에만 접근 가능") + void controller_should_only_access_service() { + ArchRule rule = layeredArchitecture() + .layer("Controller").definedBy("..controller..") + .layer("Service").definedBy("..service..") + .layer("Repository").definedBy("..repository..") + .layer("Domain").definedBy("..domain..") + .whereLayer("Controller").mayOnlyAccessLayers("Service", "Domain"); + rule.check(classes); + } + + @Test + @DisplayName("Service는 Repository와 Domain에만 접근 가능") + void service_should_only_access_repository_and_domain() { + ArchRule rule = layeredArchitecture() + .layer("Controller").definedBy("..controller..") + .layer("Service").definedBy("..service..") + .layer("Repository").definedBy("..repository..") + .layer("Domain").definedBy("..domain..") + .whereLayer("Service").mayOnlyAccessLayers("Repository", "Domain"); + rule.check(classes); + } + + @Test + @DisplayName("하위 레이어는 상위 레이어에 의존하지 않음") + void no_upward_dependencies() { + NO_CLASSES_DEPEND_ON_UPPER_LAYERS.check(classes); + } + + @Test + @DisplayName("패키지 간 순환 의존성 없음") + void no_cyclic_dependencies() { + ArchRule rule = SlicesRuleDefinition.slices() + .matching("com.runtimematrix.(*)..").should().beFreeOfCycles(); + rule.check(classes); + } +}