firebase를 통한 알림 서비스를 추가했고 다 완성되었다고 생각해서 빌드를 돌렸는데 실패해서, 디버깅했던 내용을 정리합니다.
문제 추론
처음에는 문제가 하나의 원인 때문이라고 생각했습니다. 그래서 FirebaseConfig가 test코드에서 자동으로 등록되는 게 문제로 보여서 하나만 제외시켜 주면 되겠거니 했는데 아무리 해도 해결이 안 되었습니다. 4시간 동안을 혼자 생각했던 문제 해결방안과 gpt가 제시해 준 문제 해결방안을 시도해 봤지만 결과적으로는 해결되지 않았습니다. 그렇게 다음날에 멘탈을 잡고 천천히 하나씩 문제를 구글링을 통해서 추론해 나갔습니다.
CalendarApplicationTests > contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException at ConfigurationClassParser.java:544
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180
여러 테스트 클래스들의 오류 중에 공통적으로 나타난 문제는 BeanDefinitionStoreException과 IllegalArgumentException at PropertyPlaceholderHelper가 나왔습니다.
첫 번째 시도
@EnableAutoConfiguration(exclude = {
FirebaseConfig.class
})
해당 코드를 사용해서 제거해 봤지만
Caused by: java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:
- com.chpark.chcalendar.config.FirebaseConfig
이렇게 옳은 방법은 아니었습니다. 일반적인 @Configuration 클래스라서 자동 구성 클래스가 아니므로 제외할 수 없었습니다. 그렇다면 @Configuration을 적용한 커스텀 파일을 제외하는 방법을 찾아보았습니다.
두 번째 시도
@TestPropertySource(locations = "classpath:application-test.yml")
따로 test용으로 다른 .env에 있는 환경변수들을 못 불러와서 문제가 생기는 걸 방지하려고 시도해 봤지만 빌드 시에는 해당 설정이 먹지 않아서 실패했습니다.
결국에는 빌드 환경에서 테스트 코드들이 작동할 때 환경변수를 못 받아오는 게 문제니, 반대로 오히려 받아올 수 있게 만들어주자라는 생각을 했습니다.
세 번째 시도
package com.chpark.chcalendar;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DotenvInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {
// 프로젝트 루트의 .env 파일을 읽어옵니다.
List<String> lines = Files.readAllLines(Paths.get(".env"));
Map<String, Object> props = new HashMap<>();
for (String line : lines) {
line = line.trim();
if (line.isEmpty() || line.startsWith("#")) {
continue;
}
String[] parts = line.split("=", 2);
if (parts.length == 2) {
props.put(parts[0].trim(), parts[1].trim());
}
}
// "dotenv"라는 이름으로 프로퍼티 소스를 추가합니다.
applicationContext.getEnvironment().getPropertySources()
.addFirst(new MapPropertySource("dotenv", props));
} catch (Exception e) {
// .env 파일이 없으면 예외를 무시합니다.
e.printStackTrace();
}
}
}
@SpringBootTest
@ContextConfiguration(initializers = DotenvInitializer.class)
class CalendarApplicationTests {
@Test
void contextLoads() {
}
}
@Value("${firebase.service-account-file}")
String serviceAccountFile;
오히려 반대로 .env파일을 인식시켜 줬습니다. FirebaseConfig를 자동 등록을 하려 했지만 .env에 등록된 환경변수를 불러오지 못하니 등록하는 데에 문제가 생겼다고 생각했습니다. 그렇게 DotenvInitializer를 통해서 테스트 실행 전에 .env 파일을 읽어서 FirebaseConfig가 필요한 프로퍼티 값을 올바르게 받아서, placeholder 오류를 해결하게 되었습니다. 결국에는 빌드할 때에도 테스트 코드가 정상적으로 통과되었고 정상적으로 빌드를 할 수 있게 되었습니다.
마무리
어떻게 해결할지 막막했지만 오류 내용을 꼼꼼히 읽고 어떤 것 때문인지 하나씩 추론해 가면서 해결하다 보면 더욱 빠르게 해결할 수 있음을 더 느끼게 되었습니다. 한길로만 새지 않고 다른 방법도 생각을 빠르게 해야겠다고 느낀 디버깅이었던 것 같습니다.
'Backend Programming' 카테고리의 다른 글
CI/CD? 배포 자동화를 해보자 (0) | 2024.12.13 |
---|---|
EC2를 활용한 HTTPS 및 도메인 설정 (3) | 2024.12.12 |
이메일 인증을 위한 Redis 설정과 문제 해결 과정 (0) | 2024.12.07 |
라우팅과 라우팅 테이블의 이해 (0) | 2024.11.28 |
JPA 영속성 컨텍스트 (3) | 2024.11.01 |