반응형

🔍 ArchUnit란 무엇인가?

소프트웨어 개발에서 아키텍처는 시스템의 핵심 구조를 정의합니다. 그러나 규모가 커질수록 아키텍처 규칙을 준수하기 어려워집니다.

여기서 ArchUnit이 등장합니다. ArchUnit은 Java 기반의 아키텍처 테스트 라이브러리로, 코드 내 구조적 규칙을 설정하고 이를 자동으로 검증할 수 있게 합니다. 이를 통해 프로젝트 내 아키텍처가 의도대로 유지되며, 유지보수성을 높이는 데 큰 기여를 합니다.

이번 글에서는 ArchUnit을 사용한 단위 테스트 설정 및 주요 사용법을 살펴보고, 실제 프로젝트에서 적용하는 방법을 단계별로 설명하겠습니다.

Java ArchUnit를 이용한 단위 테스트

 

 

📝 ArchUnit의 기본 원리와 장점

ArchUnit의 주요 장점은 코드와 아키텍처 간의 일관성을 유지하고, 이를 통해 코드 품질을 높일 수 있다는 점입니다. 규칙을 코드화하여 프로젝트 전체의 코드 구조가 요구 사항과 일치하는지 확인할 수 있습니다.

ArchUnit 특징 설명
코드 기반 규칙 정의 Java 또는 Kotlin 코드로 아키텍처 규칙을 정의하여 유지 보수성을 높입니다.
자동 검증 규칙을 정의한 후 자동으로 실행되어 일관성을 유지합니다.
테스트 통합 JUnit과 같은 기존의 테스트 프레임워크와 통합이 용이합니다.
유연한 규칙 설정 패키지 구조, 클래스 의존성, 접근 수준 등 다양한 규칙을 설정할 수 있습니다.

 

 

🛠 ArchUnit 설치 및 기본 설정

ArchUnit은 Maven과 Gradle 프로젝트에서 쉽게 설정할 수 있습니다. 아래 예시는 Maven과 Gradle 프로젝트에 ArchUnit을 설정하는 방법입니다.

Maven 설정

<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5-api</artifactId>
    <version>0.23.1</version>
    <scope>test</scope>
</dependency>

Gradle 설정

testImplementation 'com.tngtech.archunit:archunit-junit5-api:0.23.1'

위 설정을 통해 ArchUnit의 JUnit5 지원 모듈을 추가할 수 있습니다.

 

 

🚀 ArchUnit의 핵심 기능: 단위 테스트 작성하기

ArchUnit을 활용해 규칙을 정의하고 이를 테스트할 수 있습니다. 단위 테스트를 작성하여 코드 구조가 의도한 대로 유지되는지 검증할 수 있습니다. 주요 기능에는 패키지 의존성 규칙, 클래스 계층 구조 규칙, 접근 제한 규칙 등이 있습니다.

1. 패키지 의존성 규칙

패키지 간의 의존성을 정의하여 특정 패키지가 다른 패키지에 접근하지 못하게 규정할 수 있습니다.

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.dependencies.SlicesRuleDefinition;
import org.junit.jupiter.api.Test;

class PackageDependencyTest {
    @Test
    void 패키지_순환_의존성_검증() {
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example");

        ArchRule rule = SlicesRuleDefinition.slices()
            .matching("com.example.(*)..")
            .should().beFreeOfCycles();

        rule.check(importedClasses);
    }
}

위 코드는 com.example 패키지 내에서 순환 의존성이 발생하지 않도록 테스트합니다.

 

2. 클래스 계층 구조 규칙

특정 클래스가 반드시 특정 인터페이스를 구현하거나 부모 클래스를 상속하도록 강제할 수 있습니다.

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import org.junit.jupiter.api.Test;

class ClassHierarchyTest {
    @Test
    void 서비스_클래스_규칙_검증() {
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example.service");

        ArchRule rule = ArchRuleDefinition.classes()
            .that().resideInAPackage("..service..")
            .should().implement(ServiceInterface.class);

        rule.check(importedClasses);
    }
}

이 테스트는 service 패키지에 속한 클래스들이 ServiceInterface 인터페이스를 구현하도록 강제합니다.

 

3. 접근 제한 규칙

특정 패키지의 클래스나 메서드에 대한 접근 제한을 설정할 수 있습니다.

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import org.junit.jupiter.api.Test;

class AccessControlTest {
    @Test
    void 컨트롤러_접근_규칙_검증() {
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example");

        ArchRule rule = ArchRuleDefinition.noClasses()
            .that().resideInAPackage("com.example.controller")
            .should().accessClassesThat().resideInAPackage("com.example.repository");

        rule.check(importedClasses);
    }
}

위 테스트는 Controller 계층이 Repository 계층에 직접 접근하지 않도록 규정합니다.

 

 

📊 ArchUnit의 규칙 설정과 활용 사례

현업에서 자주 사용되는 규칙 설정과 ArchUnit의 실제 활용 예시를 소개합니다. 이와 같은 규칙 설정을 통해 개발팀 전체의 코드 품질을 향상할 수 있습니다.

규칙 설정 설명
레이어드 아키텍처 규칙 특정 계층 간 접근 제한을 설정하여 MVC 패턴을 따르도록 강제합니다.
순환 의존성 제거 패키지 내 클래스가 순환 참조되지 않도록 설정합니다.
특정 클래스 금지 보안 문제나 다른 이유로 특정 클래스의 사용을 금지합니다.
패키지 명명 규칙 패키지 이름을 명명 규칙에 맞게 유지하도록 설정합니다.

 

 

🧩 ArchUnit을 통해 아키텍처 유지 보수하기

ArchUnit의 규칙을 사용하면 아키텍처 준수 여부를 지속적으로 확인할 수 있습니다. 팀원들이 코드를 수정할 때마다 ArchUnit 테스트가 자동으로 실행되므로, 실수로 아키텍처가 깨지거나 규칙이 무시되는 일을 방지할 수 있습니다. 이를 통해 코드의 일관성과 유지 보수성을 향상시킬 수 있습니다.

ArchUnit을 활용한 CI/CD 통합

ArchUnit 테스트는 CI/CD 파이프라인에 쉽게 통합될 수 있습니다. 테스트 자동화를 통해 배포 전 아키텍처 규칙을 항상 검증할 수 있습니다. 예를 들어, GitHub Actions 또는 Jenkins와 같은 툴에서 ArchUnit 테스트를 포함한 빌드 파이프라인을 구성하면 코드 품질을 지속적으로 유지할 수 있습니다.

 

 

✅ ArchUnit 활용의 Best Practices

ArchUnit을 효과적으로 사용하기 위한 몇 가지 팁을 정리했습니다.

  • 테스트 코드 리뷰: ArchUnit 규칙은 테스트 코드로 작성되므로 리뷰를 통해 추가 개선이 가능합니다.
  • 점진적 적용: 기존 프로젝트에 ArchUnit을 적용할 때는 주요 규칙부터 점진적으로 추가하는 것이 좋습니다.
  • 문서화 및 공유: 정의한 규칙을 문서화하고, 팀 내에서 공유하여 모든 팀원이 이해하도록 합니다.
  • 커스텀 규칙 작성: 기본 제공되는 규칙 외에도 프로젝트에 맞는 커스텀 규칙을 작성하여 일관성을 높입니다.

 

 

❓ 자주 묻는 질문 (Q&A)

Q1. ArchUnit을 어떤 프로젝트에 적용하면 좋을까요?

A1. ArchUnit은 규모가 크거나, 구조적 일관성이 중요한 프로젝트에 유용합니다. 특히 레이어드 아키텍처를 사용하는 프로젝트에서 효과적입니다.

Q2. ArchUnit 규칙을 변경하면 기존 코드에 문제가 생기나요?

A2. 새 규칙 추가 시 기존 코드와의 충돌이 있을 수 있습니다. 이때 테스트 결과를 검토하며 규칙을 조정하거나 코드를 리팩터링하는 것이 좋습니다.

Q3. ArchUnit의 성능에 대한 우려가 있나요?

A3. 테스트의 양이 많아질 경우 빌드 시간이 길어질 수 있으므로, 중요한 규칙을 위주로 적용하고 불필요한 테스트는 지양합니다.


Java ArchUnit은 코드와 아키텍처가 일치하는지 지속적으로 확인할 수 있는 강력한 도구입니다. 이를 통해 개발팀은 코드의 일관성을 유지하며 유지 보수성을 높일 수 있습니다. ArchUnit을 처음 사용해보는 분이라면, 이 글을 참고하여 프로젝트에 적용해 보시길 추천드립니다! 😊

 

 

ArchUnit 공식 가이드 링크

https://www.archunit.org/userguide/html/000_Index.html

반응형

+ Recent posts