Adventure Time - Finn 3

새소식

Spring

ApplicationTests > contextLoads() FAILED 에러 해결

  • -
SellyourunhappinessApiApplicationTests > contextLoads() FAILED
    java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
        Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:802
            Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:802
                Caused by: org.springframework.beans.factory.BeanCreationException at AutowiredAnnotationBeanPostProcessor.java:514
                    Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:180

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

> Task :sellyourunhappiness-api:test FAILED

 

단위 테스트를 작성하고 전체 프로젝트 빌드를 했더니 위와 같은 에러가 발생했다..

 

어떤 원인이 문제인지 확인해보려고하는데 찾아봐야 할 부분이 너무 많아서 계속 삽질 중이다,,

 

가장 일반적인 이유 중 하나는 프로퍼티 설정과 관련된 문제라고합니다. 

PropertyPlaceholderHelper.java:180를 보면 프로퍼티 관련 문제일 가능성이 있습니다. 이 경우, Spring의 프로퍼티 설정이나 @Value 어노테이션을 사용하여 프로퍼티 값을 주입하려고 할 때, 해당 프로퍼티가 정확하게 설정되지 않았거나 읽을 수 없는 경우에 발생할 것이라해서 좀 더 자세한 에러로그를 확인하기 위해 ./gradlew test -i로 스택을 찍어보겠습니다.

 

Caused by:
        org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file [/Users/bag-yunchan/Desktop/sell-your-unhappiness-back/sellyourunhappiness-api/build/classes/java/main/sellyourunhappiness/global/config/SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'customOAuth2LoginSuccessHandler' defined in URL [jar:file:/Users/bag-yunchan/Desktop/sell-your-unhappiness-back/sellyourunhappiness-core/build/libs/sellyourunhappiness-core-0.0.1-SNAPSHOT-plain.jar!/sellyourunhappiness/core/security/handler/CustomOAuth2LoginSuccessHandler.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'jwtService': Injection of autowired dependencies failed
            at app//org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:802)
            at app//org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:241)
            at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
            at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191)
            at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
            at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
            at app//org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
            at app//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
            at app//org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
            at app//org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
            at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
            at app//org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:960)
            at app//org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)

 

로그를 찍어보니까 securityConfig 관련 빈 생성 문제와 CustomOAuth2LoginSuccessHandler, jwtService 의존성 및 프로퍼티설정이 잘못됐다고 나왔다.

 

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customOAuth2LoginSuccessHandler' defined in URL
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jwtService': Injection of autowired dependencies failed
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.token.key' in value "${jwt.token.key}"

 

아마도 @WebMvcTest를 사용해서 UserController에서 필요한 의존성들을 주입하면서 관련 에러들이 발생한 것 같다.

 

 

일단 우리 프로젝트는 멀티모듈을 사용하고있기때문에 상위 모듈의 application-api.yml 과 하위모듈의 application-core.yml이 둘다 잘 로드 되는지 확인해보자.

 

나는 두개의 yml 을 로드해야하기때문에 SpringApplication에 다음과 같이 설정해줬습니다.

@EnableJpaAuditing
@SpringBootApplication
public class SellyourunhappinessApiApplication {
    public static void main(String[] args) {
        System.setProperty("spring.config.name","application-api,application-core");
        SpringApplication.run(SellyourunhappinessApiApplication.class, args);

    }
}

 

 

 

디버거를 통해 로그를 찍어보니까 프로퍼티들은 둘 다 잘 로드되고있는 것 같다. 

 

Properties: {PATH=/opt/homebrew/opt/openjdk@17/bin:/usr/local/opt/openjdk@17/bin:/usr/local/opt/openjdk@17/bin:/opt/local/bin:/opt/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/usr/local/mysql/bin, MANPATH=/opt/local/share/man:/opt/homebrew/share/man:/opt/homebrew/share/man:::, HOMEBREW_PREFIX=/opt/homebrew, COMMAND_MODE=unix2003, LOGNAME=bag-yunchan, HOMEBREW_REPOSITORY=/opt/homebrew, PWD=/Users/bag-yunchan/Desktop/sell-your-unhappiness-back, XPC_SERVICE_NAME=application.com.jetbrains.intellij.4745075.4745799, INFOPATH=/opt/homebrew/share/info:/opt/homebrew/share/info:, __CFBundleIdentifier=com.jetbrains.intellij, SHELL=/bin/zsh, PAGER=less, LSCOLORS=Gxfxcxdxbxegedabagacad, HOMEBREW_CELLAR=/opt/homebrew/Cellar, OLDPWD=/, USER=bag-yunchan, ZSH=/Users/bag-yunchan/.oh-my-zsh, TMPDIR=/var/folders/7r/62c0y0q9671_t6f8040167lr0000gn/T/, SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.GWsYzy9b7Z/Listeners, XPC_FLAGS=0x0, __CF_USER_TEXT_ENCODING=0x1F5:0x3:0x33, LESS=-R, LC_CTYPE=ko_KR.UTF-8, LS_COLORS=di=1;36:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43, HOME=/Users/bag-yunchan}
Property Source: random
Properties: java.util.Random@54d0d561
Property Source: Config resource 'class path resource [application-core.yml]' via location 'optional:classpath:/'
Properties: {spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver, spring.datasource.url=jdbc:mysql://database-test.cttv6gkl7biw.ap-northeast-2.rds.amazonaws.com:3306/test?serverTimezone=Asia/Seoul&characterEncoding=UTF-8, spring.datasource.username=admin, spring.datasource.password=qwer1234, spring.jpa.hibernate.ddl-auto=create, spring.jpa.properties.hibernate.show_sql=true, spring.jpa.properties.hibernate.format_sql=true, spring.jpa.properties.hibernate.default_batch_fetch_size=100, spring.jpa.open-in-view=false, spring.profiles.active=local, logging.level.org.hibernate.sql=trace, jwt.secret=vbZrJPe/dxRnrun2HoO16XFQEHwF5r72e6HBoAF4+u43V9fwua9Ktu5xULvwsdQTuo70xGOhljXv1LqNt1ZoCg==, jwt.access.expiration=360000, jwt.access.header=Authorization, jwt.refresh.expiration=1209600000, jwt.refresh.header=Authorization-refresh}
Property Source: Config resource 'class path resource [application-api.yml]' via location 'optional:classpath:/'
Properties: {spring.h2.console.enabled=true, spring.h2.console.path=/h2-console, spring.security.oauth2.client.registration.google.client-id=330207848617-5q422g8mp74jdfavrlfon95cv488thuf.apps.googleusercontent.com, spring.security.oauth2.client.registration.google.client-secret=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, spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/google, spring.security.oauth2.client.registration.google.authorization-grant-type=authorization_code, spring.security.oauth2.client.registration.google.scope[0]=profile, spring.security.oauth2.client.registration.google.scope[1]=email, sellyourunhappiness.slack.token=T06C30DKWR1/B06EHSJA9GV/EmcTfUsZbizVV5hvtcZ92IzT}
Disconnected from the target VM, address: '127.0.0.1:60780', transport: 'socket'

 

 

그렇다면 왜 도대체 application-core.yml에 설정되있는 jwt.secret 을 @Value에서 못받아갈까? 애플리케이션을 실행할땐 문제가없는데 빌드시에만 문제가 발생하고있다.

 

여러 해결책들을 찾아보니까  build.gradle에서 아래와 같은 부분을 지우는 방법은 근본적인 해결책을 찾는 방법들이 아니기 때문에 근본적인 원인을 고쳐야될 것 같다..

tasks.named('test') {
    useJUnitPlatform()
}
@Test
void contextLoads() {
}

 

 

테스트 코드에서 해당 빈들을 의존성 주입을 해주면서 해결이 되었다.

 

하지만 사용하지 않는 빈들을 의존성 주입해서 적용하는 방법은 좋지 않은 방법이니까 해당 빈들을 주입안해도되게 코드를

리팩토링해보자..

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.