[JUnit] Error Note : @DataJpaTest 사용시 datasource 설정 오류

DEINGVELOP·2022년 9월 7일
0
post-custom-banner

작성한 코드

@DataJpaTest
class AnswerRepositoryTest {

    AnswerRepository answerRepository;

    Member mockMember = Member.builder()
            .username("cheolsu")
            .password("password")
            .nickname("김철수")
            .build();

    Interview mockInterview = Interview.builder()
            .question("스프링이란?")
            .answer("웹 어플리케이션을 만들 수 있는 자바 기반의 웹 프레임워크이다.")
            .subTopic(SubTopic.builder()
                    .topic(Topic.builder()
                            .name("BACKEND")
                            .build())
                    .name("SPRING")
                    .build())
            .build();

    @BeforeEach
    void setUp() {

        MockMemberRepository memberRepository = new MockMemberRepository();
        memberRepository.save(mockMember);

        MockInterviewRepository interviewRepository = new MockInterviewRepository();
        interviewRepository.save(mockInterview);
    }

    @Test
    @DisplayName("답변 저장하기")
    void saveAnswer() {

        // given
        Answer answer = Answer.builder()
                .interview(mockInterview)
                .member(mockMember)
                .content("스프링은 자바 기반 프레임워크입니다.")
                .publicTF(true)
                .build();

        // when
        Answer savedAnswer = answerRepository.save(answer);

        // then
        Assertions.assertThat(answer).isSameAs(savedAnswer);
        Assertions.assertThat(answer.getContent()).isEqualTo(savedAnswer.getContent());
        Assertions.assertThat(answer.isPublicTF()).isEqualTo(savedAnswer.isPublicTF());
        Assertions.assertThat(answerRepository.count()).isEqualTo(1);
    }
}

발생한 오류

Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
	at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$8(ClassBasedTestDescriptor.java:363)
	...(이하 생략)

문제 원인

처음엔 @DataJpaTest Annotation을 제거하니 해결되었다. 그러나 Repository 단위 테스트를 위해서는 해당 Annotation을 사용해야 한다고 판단했기 때문에 해결하여 적용해보기로 했다. (@DataJpaTest를 이용하면 추가로 트랜잭션을 선언해줄 필요가 없고, 테스트가 끝나면 자동으로 롤백이 적용이 되기 때문이다.)

이에 원인을 찾아보니, @DataJpaTest는 기본적으로 내장된 메모리 데이터베이스를 이용해 테스트를 실행해주는 원리라고 한다. 그런데 나는 물리적인 MySQL 데이터베이스를 연결해서 테스트를 할려고 하여 발생한 문제였다.

이는 내장된 메모리 데이터베이스로 바꾸어 문제를 해결할 수도 있다.

그러나 MySQL 데이터베이스를 연결해서 테스트를 하기 위해서는 설정을 재정의해야 하는 부분이 있다.

AutoConfigureTestDatabase

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ImportAutoConfiguration
@PropertyMapping("spring.test.database")
public @interface AutoConfigureTestDatabase {

    @PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE)
    Replace replace() default Replace.ANY;

    EmbeddedDatabaseConnection connection() default EmbeddedDatabaseConnection.NONE;

    enum Replace {
        ANY,
        AUTO_CONFIGURED,
        NONE
    }

connection()

  • embeddedDatabase를 연결해줌

Replace : embeddedDatabase에 관한 설정

  • ANY : 자동, 수동 상관 없이 DataSource Bean을 교체함
  • AUTO_CONFIGURED : 자동 구성된 경우에만 DataSource Bean을 교체함
  • NONE : DataSource를 교체하지 않음

EmbeddedDatabaseConnection

public enum EmbeddedDatabaseConnection {

    NONE(null, null, null, (url) -> false),

    H2(EmbeddedDatabaseType.H2, DatabaseDriver.H2.getDriverClassName(),
            "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", (url) -> url.contains(":h2:mem")),

    DERBY(EmbeddedDatabaseType.DERBY, DatabaseDriver.DERBY.getDriverClassName(), "jdbc:derby:memory:%s;create=true",
            (url) -> true),

    HSQLDB(EmbeddedDatabaseType.HSQL, DatabaseDriver.HSQLDB.getDriverClassName(), "org.hsqldb.jdbcDriver",
            "jdbc:hsqldb:mem:%s", (url) -> url.contains(":hsqldb:mem:"));

➡ 제공하는 DatabaseType : H2, DERBY, HSQLDB


해결

@DataJpaTest 어노테이션 밑에 @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 주석을 통해 AutoConfigureTestDatabase에서 설정을 EmbeddedDatabase를 사용하지 않도록 바꿔주었다.

Replace 값을 NONE으로 설정해주면서 EmbeddedDatabase를 찾아 설정하지 않고 기존 애플리케이션에서 사용한 DataSource를 등록하도록 설정이 변경된다.





참고자료

post-custom-banner

0개의 댓글