@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 데이터베이스를 연결해서 테스트를 하기 위해서는 설정을 재정의해야 하는 부분이 있다.
@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()
➡ Replace
: embeddedDatabase에 관한 설정
ANY
: 자동, 수동 상관 없이 DataSource Bean을 교체함AUTO_CONFIGURED
: 자동 구성된 경우에만 DataSource Bean을 교체함NONE
: DataSource를 교체하지 않음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를 등록하도록 설정이 변경된다.
참고자료