ArchUnit

Noah·2022년 8월 24일
0

Application Test Study

목록 보기
6/6

ArchUnit

  • 애플리케이션의 아키텍처를 테스트 할 수 있는 오픈 소스 라이브러리

  • 패키지 / 클래스 / 레이어 / 슬라이스간의 의존성을 확인하는 기능 제공

    • 레이어
      • 계층을 의미함으로써 각각의 구성 요소들이 각 레이어에 수평적으로 구조화 되어있는 형태
    • 슬라이스
      • 애플리케이션의 동작을 관심 있는 특정 부분으로 제한 하는 기법
      • 슬라이스 단위 별로 영향을 받는 부분을 찾아서 품질을 높일 수 있다.
  • 최대한 상호 참조(Circular Dependency) 가 없도록 해야하며, 이를 찾아내기 위해 사용 가능

    • Circular Dependency
      • 예시) User가 Team을 참조하고 있는데, Team도 User를 참조하는 경우
      • User를 빌드 시 Team도 필드해야하고 Team을 빌드 시, User를 빌드하게 됨으로 무한 루프에 빠져버림
  • ArchUnit 사용 예시

    1. A 패키지가 B or C or D 에서만 사용 되는지 확인할 때
    2. Service라는 이름의 클래스들이 Controller 또는 Service 이름을 가진 클래스에서만 참조하고 있는지 확인할 때
    3. A 클래스가 A와 관련된 패키지 안에 들어 있는지 확인할 때
    4. A라는 어노테이션을 선언한 메소드만 특정 패키지 또는 어노테이션을 가진 클래스를 호출하고 있는지 확인할 때
    5. 특정한 스타일의 아키텍처를 보이고 있는지 확인할 때
  • 위 사용 예시를 테스트하기 위해서 일정한 룰을 만들어서 확인할 수 있다!

ArchUnit 설치

  • Maven 기준 pom.xml에 아래의 dependency만 추가하면 끝!

    <JUnit5용 ArchUnit>

    <dependency>
        <groupId>com.tngtech.archunit</groupId>
        <artifactId>archunit-junit5-engine</artifactId>
        <version>0.12.0</version>
        <scope>test</scope>
    </dependency>

ArchUnit 사용법

  • 아래 코드 예시를 보면서 사용법을 알아 봅시다.

    1~3 순서로 진행하면 됩니다

    @Test
    public void Services_should_only_be_accessed_by_Controllers() {

        //1. 특정 패키지에 해당하는 클래스를(바이트 코드를 통해) 읽고
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example.demo");

        //2. 확인할 규칙을 정의하고
        ArchRule myRule = classes()
                .that().resideInAPackage("..service..")
                .should().onlyBeAccessed().byAnyPackage("..controller..", "..service..");

        //3. 읽어들인 클래스들이 정한 규칙을 따르는지 확인하기
        myRule.check(importedClasses);
    }
  1. 특정 패키지에 해당하는 클래스를 (바이트 코드를 통해) 읽고
    • ClassFileImporter().importPackages(ava.lang.String... packages)
      • String으로 지정한 패키지에서 가져온 클래스들을 바이트 코드로 읽어 들임
  2. 확인할 규칙을 정의하고
    • resideInAPackage("..service..") : 서비스 패키지 않에 있는 클래스들은
    • .should().onlyBeAccessed() : 참조 되어야 한다
    • .byAnyPackage(""..controller..", "..service.."") : 컨트롤러랑 서비스 패키지 안에서
  3. 읽어들인 클래스들이 정한 규칙을 따르는지 확인
    • 2번에서 지정한 룰을 .check("읽어들인 바이트 코드 형식의 클래스")
  • 추가 정보!

    • JUnit 5 확장팩을 이용해서 ArchUnit 사용하기

      • @AnalyzeClasses : 클래스를 읽어들여서 확인할 패키지 설정

        위 사용법의 1번에 해당

      • @ArchTest : 확인할 규칙 정의

        위 사용법의 2번에 해당

실습

  1. ArchUnit를 이용해서 패키지 의존성 확인

    • 패키지 의존성을 확인하기 위해서 ArchUnit을 사용해 코드를 작성하면 된다.

          @Test
          void packageDependencyTests() {
              JavaClasses classes = new ClassFileImporter().importPackages("com.example.testpractice");
      
              ArchRule userPackageRule = classes().that().resideInAPackage("..user..")
                      .should().onlyBeAccessed().byClassesThat()
                      .resideInAnyPackage("..post..", "..comment..");
      
              userPackageRule.check(classes);
          }
  1. JUnit5 확장팩을 사용해서 패키지 의존성 확인

    • 확장팩 사용을 하기 위해서는 아래의 두 어노테이션을 사용한다

      1. @AnalyzeClasses : 클래스를 읽어들여서 확인할 패키지 설정
      2. @ArchTest : 확인할 규칙 정의
    • 위 1번에서 사용한 코드를 어노테이션을 이용해서 더욱 간결하게 표현하고 테스트 할 수 있다

      @AnalyzeClasses(packagesOf = App.class)
      public class ArchTests {
      
          @ArchTest
          ArchRule domainPackageRule = classes().that().resideInAPackage("..domain..")
                  .should().onlyBeAccessed().byClassesThat()
                  .resideInAnyPackage("..study..", "..member..", "..domain..");
      
          @ArchTest
          ArchRule memberPackageRule = noClasses().that().resideInAPackage("..domain..")
                  .should().accessClassesThat().resideInAPackage("..member..");
      
          @ArchTest
          ArchRule studyPackageRule = noClasses().that().resideOutsideOfPackage("..study..")
                  .should().accessClassesThat().resideInAnyPackage("..study..");
      
          @ArchTest
          ArchRule freeOfCycles = slices().matching("..inflearnthejavatest.(*)..")
                  .should().beFreeOfCycles();
      
      }

ArchUnit의 추가 정보!

  • ArchUnit은 JUnit5의 확장판이다
  • 확장판을 만들때 대부분은 @ExtendWith를 사용해서 확장하곤 하는데 @AnalyzeClasses 또는 @ArchTest는 JUnit의 엔진자체를 확장해서 사용한다!
profile
BackEnd 개발자가 되기 위해 공부중입니다!

0개의 댓글