[Spring] CH 5 플러스 Spring 과제 초기 설정 트러블슈팅

임선구·2026년 6월 19일

트러블슈팅

목록 보기
13/16

들어가며

CH 5 플러스 Spring 과제를 진행하면서 본격적인 기능 구현에 들어가기 전, 프로젝트 실행 환경을 맞추는 과정에서 몇 가지 문제가 발생했다.

이번 과제는 기존 GitHub Repository를 fork한 뒤 local로 clone해서 진행하는 방식이었다.
프로젝트를 처음 실행하고 테스트를 돌리는 과정에서 Gradle Wrapper, Java 버전, JWT 설정값 관련 문제가 연속으로 발생했고, 이를 해결한 과정을 정리해보려고 한다.


1. Gradle Wrapper 설정 파일 누락 문제

문제 상황

프로젝트를 clone한 뒤 테스트를 실행했다.

./gradlew test

그런데 아래와 같은 에러가 발생했다.

Wrapper properties file '.../gradle/wrapper/gradle-wrapper.properties' does not exist.

원인

프로젝트에는 gradlew 파일과 gradle-wrapper.jar 파일은 존재했지만, Gradle Wrapper가 어떤 Gradle 버전을 사용할지 정의하는 gradle-wrapper.properties 파일이 없었다.

Gradle Wrapper가 정상적으로 동작하려면 보통 아래 구조가 필요하다.

gradle
└── wrapper
    ├── gradle-wrapper.jar
    └── gradle-wrapper.properties

하지만 현재 프로젝트에는 gradle-wrapper.properties가 누락되어 있어서 ./gradlew 명령어를 실행할 수 없었다.

해결

gradle/wrapper/gradle-wrapper.properties 파일을 직접 생성하고 Gradle 배포 URL을 설정했다.

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

이후 다시 Gradle 명령어를 실행하자 Wrapper 관련 에러는 해결되었다.


2. Java 버전 불일치 문제

문제 상황

Gradle Wrapper 문제를 해결한 뒤 다시 테스트를 실행했다.

./gradlew test

이번에는 아래와 같은 에러가 발생했다.

Unsupported class file major version 67

원인

major version 67은 Java 23에 해당한다.

현재 터미널에서 Java 23이 사용되고 있었고, 프로젝트와 Gradle 환경은 Java 17 기준으로 맞추는 것이 적절했다.
즉, 프로젝트에서 기대하는 Java 버전과 실제 터미널에서 사용하는 Java 버전이 달라서 문제가 발생한 것이다.

해결

터미널과 IntelliJ 설정을 Java 17로 맞췄다.

터미널에서는 JAVA_HOME을 Java 17로 설정했다.

export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH="$JAVA_HOME/bin:$PATH"

이후 확인했다.

java -version

또한 IntelliJ에서도 아래 설정을 Java 17로 맞췄다.

  • Project SDK: Java 17
  • Gradle JVM: Java 17

이후 Gradle daemon을 정리하고 다시 테스트를 실행했다.

./gradlew --stop
./gradlew clean test

Java 버전 문제는 해결되었다.


3. JWT secret key 누락 문제

문제 상황

Java 버전 문제를 해결한 뒤 테스트를 실행했지만, 이번에는 Spring Context 로딩 중 실패가 발생했다.

에러의 핵심은 다음과 같았다.

PropertyPlaceholderHelper

프로젝트 코드를 확인해보니 JwtUtil에서 아래 설정값을 사용하고 있었다.

@Value("${jwt.secret.key}")
private String secretKey;

원인

테스트 환경에서 jwt.secret.key 값이 설정되어 있지 않았다.

Spring은 ${jwt.secret.key} 값을 찾아 주입해야 하는데, 테스트 실행 시 해당 설정값을 찾지 못해 ApplicationContext 로딩에 실패했다.

해결

테스트 전용 설정 파일을 생성했다.

src/test/resources/application.properties

그리고 테스트용 JWT secret key를 추가했다.

처음에는 일반 문자열을 넣었지만, 이후 Base64 디코딩 과정에서 다시 오류가 발생했다.

IllegalArgumentException at Base64.java

JwtUtil 내부에서 secret key를 Base64로 디코딩하고 있었기 때문에, 일반 문자열이 아니라 Base64 형식의 값이 필요했다.

그래서 테스트용 값을 Base64 형식으로 수정했다.

jwt.secret.key=c3BhcnRhLXNwcmluZy1wbHVzLXRlc3Qtand0LXNlY3JldC1rZXktMTIzNDU2Nzg5MA==

이후 Spring Context가 정상적으로 로딩되었다.


4. Controller 테스트 기대값 불일치 문제

문제 상황

초기 설정 문제를 해결한 뒤에도 아래 테스트가 실패했다.

todo_단건_조회_시_todo가_존재하지_않아_예외가_발생한다()

테스트 코드를 확인해보니 서비스에서 예외를 던지도록 설정되어 있었다.

when(todoService.getTodo(todoId))
        .thenThrow(new InvalidRequestException("Todo not found"));

하지만 테스트의 기대 응답은 200 OK로 되어 있었다.

.andExpect(status().isOk())

원인

InvalidRequestExceptionGlobalExceptionHandler에서 400 BAD_REQUEST로 처리되고 있었다.

즉 실제 응답은 400 BAD_REQUEST인데, 테스트는 200 OK를 기대하고 있었기 때문에 실패한 것이다.

해결

테스트 기대값을 실제 예외 처리 결과에 맞게 수정했다.

.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.status").value(HttpStatus.BAD_REQUEST.name()))
.andExpect(jsonPath("$.code").value(HttpStatus.BAD_REQUEST.value()))
.andExpect(jsonPath("$.message").value("Todo not found"));

수정 후 테스트가 정상적으로 통과했다.


최종 결과

위 문제들을 해결한 뒤 전체 테스트를 다시 실행했다.

./gradlew clean test

결과적으로 테스트가 정상적으로 통과했다.

BUILD SUCCESSFUL

정리

이번 트러블슈팅을 통해 프로젝트를 시작할 때 기능 구현만큼이나 실행 환경을 정확히 맞추는 것이 중요하다는 것을 느꼈다.

특히 다음 내용을 다시 확인할 수 있었다.

  • Gradle Wrapper는 gradle-wrapper.properties 파일이 필요하다.
  • 프로젝트 Java 버전과 터미널/IDE Java 버전이 일치해야 한다.
  • 테스트 환경에서도 필요한 설정값은 별도로 제공해야 한다.
  • JWT secret key처럼 내부에서 Base64 디코딩하는 값은 형식까지 맞춰야 한다.
  • 테스트는 실제 예외 처리 정책과 기대값이 일치해야 한다.

이번 과제에서는 초반 설정 문제를 해결한 뒤, 이후 필수 기능들을 하나씩 구현하며 전체 테스트를 통과시킬 수 있었다.

profile
끝까지 가면 내가 다 이겨

0개의 댓글