여러가지 이야기

[Spring/Spring Boot] assertj import가 안 될 때 - build.gradle 의존성 충돌 본문

study/Spring

[Spring/Spring Boot] assertj import가 안 될 때 - build.gradle 의존성 충돌

jimddong 2024. 10. 31. 02:25

assertThat()를 쓰려고 assertj를 불러오려했으나 import 자체가 안됐다. 인터넷의 어떤 방법을 써도 assertj가 안 불러와지길래, 라이브러리 자체가 build.gradle의 depenencies에서 호출되지 않았으리라 추측했다.

 

그렇다면 assertj는 어떤 의존성에 속하는 라이브러리일까?

스프링 공식 사이트의 스프링부트 의존성 관련 페이지(🔗https://docs.spring.io/spring-boot/reference/testing/test-scope-dependencies.html#page-title)를 보면, spring-boot-starter-test depencies에 AssertJ가 속해있는 것을 알 수 있다.
그래서 'spring-boot-starter-test를 dependencies에 이미 추가했는데 왜 문제가 발생했을까?' 하고 gradle 파일을 확인해봤다. 기본적으로 spring initializer에서 프로젝트를 만들 때 추가됐을텐데 말이다.

 

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.junit.jupiter:junit-jupiter:5.8.1'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

원래 내 프로젝트의 dependency는 위와 같았다. spring-boot-starter-test가 당연히 들어가 있다. spring-boot-starter-test에 AssertJ가 포함되어 있을텐데도 문제가 해결되지 않아, 따로 assertj dependency를 아래처럼 추가했다.

 

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.junit.jupiter:junit-jupiter:5.8.1'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    testImplementation 'org.assertj:assertj-core:3.24.2'
}

 

 

IntelliJ의 Analyze Dependencies 기능

뒤늦게 build 파일의 dependency를 자세히 분석해 보니 내가 추가로 넣은 assertj와 기존 spring-boot-starter-test를 통해 들어간 assertj 라이브러리 모두가 의존성으로 들어가 있었다. 일단 다시 추가로 넣은 assertj line을 삭제시켜줬다.

 

(+ 혹시 spring-boot-starter와 spring-boot-starter-test의 버전을 자세히 적지 않아서 문제인가 싶어 버전도 추가해줬다.)

AssertJ가 라이브러리로 들어가있는데도 왜 안될까? 고민하면서 gradle 파일을 계속 수정하는 과정에서 실수로 test 코드를 implementation 부분에 적어버리고, 그냥 starter를 testImplementation에 적으니 assertj가 불러와지는 것이다.

 

 

뭔가 의존성 충돌이 일어나 생긴 문제인듯 했다...

 

여기서 잠깐, spring-boot-starter-test가 포함하는 library 목록들을 다시 보자.

spriing-boot-starter-test는 JUnit5, AssertJ, Hamcrest 등의 라이브러리들을 제공한다.

그런데 나는 앞서 @DisplayName()과 같은 어노테이션을 쓰기 위해 5.8.1 버전의 JUnit을 따로 한 번 더 dependency에 추가해줬었다.

import org.junit.jupiter.api; 부분

build.gradle에서 spring-boot-starter에서도 JUnit5를, 내가 넣은 implementation 'org.junit.jupiter:junit-jupiter:5.8.1' 이 라인에서도 JUnit을 중복으로 의존하고 있어 생긴 문제인 것이다. AssertJ 라이브러리를 포함하는 spring-boot-starter가 여기서 문제를 일으켜 내가 assertj를 import할 수가 없었다!


즉, 직접적으로 AssertJ 라이브러리에서 문제가 있던 것이 아니라, 다른 라이브러리들이 의존성 충돌을 일으키고 있어 문제가 된 것이다.

 

나는 어찌 됐든 5.8.1 버전의 JUnit을 써줘야했기에, 위처럼 두 번 JUnit을 의존하는 게 아니라, spring-boot-starter의 JUnit을 특정 JUnit으로 변경해주는 코드로 바꿔 충돌을 해결했다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter:3.2.1'
    testImplementation('org.springframework.boot:spring-boot-starter-test:3.2.1') {
        exclude group: 'org.junit.jupiter', module: 'junit-jupiter'
    }
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'  // 원하는 버전 사용
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

 


결론

1. 의존성 충돌을 주의하자.

  • 필요할 것 같아서라는 이유로 의존성에 넣어뒀던 것들이, 사실은 어떤 라이브러리를 가져오는지 파악하며 알고 있어야겠다고 생각했다. (ex. spring-boot-starter는 애플리케이션 기본 기능을 제공하는 spring-core, spring-beans 등의 라이브러리를 포함하고, spring-boot-starter-test는 테스트 환경을 구성하는 관련 라이브러리인 JUnit5, AssertJ, JsonPath 등을 포함한다.)
  • 특히 같은 라이브러리를 여러 의존성에서 포함하는 경우, 충돌을 막기 위해 특정 모듈을 제외하거나 버전을 지정하자.

 

2. 의존성 충돌이 의심 간다면 intelliJ의 build 파일 의존성 분석 기능을 써서 들여다보자. (무슨 라이브러리가 있는지 파악하기 아주 유용했다.)