ArchUnit 연습: Onion Architecture 아키텍처 테스트

// 実行環境
* AdoptOpenJDK 11.0.9.1+1
* JUnit 5.7.0
* ArchUnit 0.14.1

레이어 종속성


  • 의존 방향은 외부 층에서 내부 층으로 일방 통행
  • 가장 바깥 쪽 어댑터는 독립적입니다



  • Java 프로젝트의 패키지 구성





    아키텍처 테스트 구현


    package com.example;
    
    import com.tngtech.archunit.core.domain.JavaClasses;
    import com.tngtech.archunit.core.importer.ClassFileImporter;
    import com.tngtech.archunit.core.importer.ImportOption;
    import org.junit.jupiter.api.Test;
    
    import static com.tngtech.archunit.library.Architectures.onionArchitecture;
    
    class ArchitectureTest {
    
        // 検査対象のクラス
        private static final JavaClasses CLASSES =
                new ClassFileImporter()
                        .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
                        .importPackages("com.example");
    
        @Test
        void オニオンアーキテクチャのアーキテクチャテスト() {
            onionArchitecture()
                // domain.model パッケージをドメインモデル層として定義
                .domainModels("com.example.domain.model..")
                // domain.service パッケージをドメインサービス層として定義
                .domainServices("com.example.domain.service..")
                // application パッケージをアプリケーションサービス層として定義
                .applicationServices("com.example.application..")
    
                // infrastructure パッケージをインフラストラクチャ・アダプターとして定義
                .adapter("infra", "com.example.infrastructure..")
                // presentation パッケージをユーザインターフェイス・アダプターとして定義
                .adapter("ui", "com.example.presentation..")
    
                .check(CLASSES);
        }
    }
    

    아키텍처 테스트 실행 예



    테스트 실패 예 ①(도메인 서비스 → 애플리케이션 서비스에 의존)



    내부 도메인 서비스 계층의 Service 클래스가 외부 응용 프로그램 서비스 계층의 UseCase 클래스에 종속되어 있다는 아키텍처 위반을 감지한 가정에서 테스트 실패의 예입니다.
    $ ./gradlew clean check
    
    > Task :test FAILED
    
    ArchitectureTest > オニオンアーキテクチャのアーキテクチャテスト() FAILED
        java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'Onion architecture consisting of
        domain models ('com.example.domain.model..')
        domain services ('com.example.domain.service..')
        application services ('com.example.application..')
        adapter 'infra' ('com.example.infrastructure..')
        adapter 'ui' ('com.example.presentation..')' was violated (2 times):
        Constructor <com.example.domain.service.employee.EmployeeRegisterService.<init>(com.example.application.HogeUseCase)> has parameter of type <com.example.application.HogeUseCase> in (EmployeeRegisterService.java:0)
        Field <com.example.domain.service.employee.EmployeeRegisterService.hogeUseCase> has type <com.example.application.HogeUseCase> in (EmployeeRegisterService.java:0)
            at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94)
            at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:82)
            at com.tngtech.archunit.library.Architectures$LayeredArchitecture.check(Architectures.java:267)
            at com.tngtech.archunit.library.Architectures$OnionArchitecture.check(Architectures.java:538)
            at com.example.ArchitectureTest.オニオンアーキテクチャのアーキテクチャテスト(ArchitectureTest.java:560)
    
    1 test completed, 1 failed
    

    테스트 실패 예 ② (사용자 인터페이스 어댑터 → 인프라 어댑터에 의존)



    사용자 인터페이스 어댑터의 Controller 클래스가 인프라 어댑터의 Repository (Impl) 클래스에 의존하고 있다는 아키텍처 위반을 감지 한 가정에서의 테스트 실패 예.
    $ ./gradlew clean check
    
    > Task :test FAILED
    
    ArchitectureTest > オニオンアーキテクチャのアーキテクチャテスト() FAILED
        java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'Onion architecture consisting of
        domain models ('com.example.domain.model..')
        domain services ('com.example.domain.service..')
        application services ('com.example.application..')
        adapter 'infra' ('com.example.infrastructure..')
        adapter 'ui' ('com.example.presentation..')' was violated (2 times):
        Constructor <com.example.presentation.employee.EmployeeController.<init>(com.example.infrastructure.datasource.EmployeeRepositoryImpl)> has parameter of type <com.example.infrastructure.datasource.EmployeeRepositoryImpl> in (EmployeeController.java:0)
        Field <com.example.presentation.employee.EmployeeController.employeeRepository> has type <com.example.infrastructure.datasource.EmployeeRepositoryImpl> in (EmployeeController.java:0)
            at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94)
            at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:82)
            at com.tngtech.archunit.library.Architectures$LayeredArchitecture.check(Architectures.java:267)
            at com.tngtech.archunit.library.Architectures$OnionArchitecture.check(Architectures.java:538)
            at com.example.ArchitectureTest.オニオンアーキテクチャのアーキテクチャテスト(ArchitectureTest.java:560)
    
    1 test completed, 1 failed
    

    좋은 웹페이지 즐겨찾기