서비스 또는 시스템은 목적에 따라 아키텍쳐를 설계하고 이에 기반하여 구현이 됩니다. 여기서 이야기하는 아키텍쳐란 기능, 조직, 구현에 대한 법칙과 방법을 의미합니다. 깨진 유리창 이론도 있듯이 초기에 아키텍쳐가 잘 설계되어 있다 하더라도 시간이 지남에 따라 점점 망가질 수 있습니다. 이를 최대한 방지하기 위해 아키텍쳐적인 부분에 대해서도 검사를 할 필요성이 있으며, 그 방법 중에 하나가 ArchUnit 이라는 라이브러리를 활용하는 것입니다. 이번 글에서는 ArchUnit 을 활용하여 아키텍쳐 검사를 해보도록 하겠습니다.
Pull request: https://github.com/kdohyeon/crypto-labs/pull/18
의존성 추가
라이브러리 버전은 현재 기준 최신 버전인 1.0.1 을 사용했다.
dependencies {
testImplementation 'com.tngtech.archunit:archunit:1.0.1'
}
아키텍쳐 소개
app-api 기준으로 살펴보면 입력 (input) port 에만 의존해야하고 나머지 모듈에는 의존을 하면 안된다. 이에 대한 아키텍쳐 테스트를 작성해보도록 하자.
테스트 생성
아키텍쳐 검사도 테스트의 일부분이기 때문에 test 디렉토리에 생성했고, app-api 에 대한 테스트이기 때문에 crypto-apps/app-api 모듈 내 위치시켰다.
ArchUnit 으로 다양한 테스트를 해볼 수 있지만 여기서는 패키지간 의존성 테스트만 해보려고 한다. 특정 클래스가 잘못된 패키지에 의존하고 있는 경우를 찾아낼 수 있다. 이를 통해 무분별한 import 를 방지할 수 있다.
먼저 아키텍쳐 테스트를 작성하려면 규칙이 있어야 한다. 예를 들어, app-api 패키지는 application-service 패키지에 의존할 수 없다 라는 규칙을 정했다면 다음과 같이 설정할 수 있다.
@ArchTest
val controller_should_not_depend_on_service_directly =
noClasses().that()
.resideInAPackage("..controller..").should().onlyDependOnClassesThat()
.resideInAnyPackage("..service..")
.`as`("controller 는 service 에 의존할 수 없습니다. 입력 port 를 사용해주세요.")
또한 순환 의존을 방지하기 위해 아래와 같이 테스트를 작성할 수도 있다.
@ArchTest
val cycle_check =
SlicesRuleDefinition.slices().matching("kdohyeon.crypto.labs.(*)..")
.should().beFreeOfCycles()
참고
- ArchUnit User Guide: 공식 레퍼런스
'스프링 > 만들면서 배우는 실무 백엔드 개발' 카테고리의 다른 글
12. SpringBoot 에서 AOP 적용하기 (Kotlin) (0) | 2023.05.04 |
---|---|
11. Jacoco + Gradle.kts 로 테스트 커버리지 확인하기 (feat. SonarQube) (0) | 2023.04.07 |
9. 단위 테스트 작성하기 (feat. JUnit5 + MockK) (0) | 2023.04.02 |
8. JPA 적용하기 (0) | 2023.03.30 |
7. 스프링부트에서 H2 데이터베이스 연결하기 (0) | 2023.03.29 |
댓글