티스토리 뷰
Error 상황
프로젝트 환경 설정
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/awss3?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 1234
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
open-in-view: false
show-sql: true
hibernate:
format_sql: true
ddl-auto: create
JPA관련 테스트를 하기 위해 @DataJpaTest를 이용해서 테스트를 실행하고자 하였다.
테스트를 작성하고 실행을 하니 아래와 같은 에러가 발생하였다.
에러내용중에서 화살표 부분의 에러내용을 가져와봤다.
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]:
Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is java.lang.IllegalStateException:
Failed to replace DataSource with an embedded database for tests.
If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoConfigureTestDatabase.
에러내용을 보니 dataSourceScriptDatabaseInitializer인 dataSource 빈을 생성하는데 에러가 발생하고, Failed to replace DataSource with an embedded database for tests. DataSource를 내장 데이터베이스로 교체하는데에 실패했다고 한다.
If you want an embedded database please put a supported one on the classpath or tune the replace attribute of @AutoConfigureTestDatabase. 마지막으로 @AutoConfigureTestDatabase
를 살펴보라고 알려주는거 같았다.
그래서 에러를 해결하기 위해 @AutoConfigureTestDatabase
에 대해 먼저 알아보자.
@AutoConfigureTestDatabase
@AutoConfigureTestDatabase
에 대해 알아보기 위해서는 먼저 @DataJpaTest
를 살펴봐야 합니다.
DataJpaTest
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(DataJpaTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {
}
@DataJpaTest
를 사용하면 자동으로 여러 옵션들이 붙는다.
여기서 @Transactional 애노테이션도 있는걸 확인 할 수 있다. 즉 @DataJpaTest 를 사용하면 추가로 트랜잭션을 선언해줄 필요가 없고, 테스트가 끝나면 자동으로 롤백이 적용됩니다.
DataJpaTest 코드 위에 주석을 읽어보거나 여기를 살펴보면 They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource). The @AutoConfigureTestDatabase annotation can be used to override these settings. 라고 하여
번역해보자면 내장된 메모리 데이터베이스를 사용하고, @AutoConfigureTestDatabase
를 사용하면 설정을 재정의 할 수 있다고 적혀있다.
이걸 읽어보니 왜 에러가 발생했는지 알 수 있었다.
@DataJpaTest 는 기본적으로 내장된 메모리 데이터베이스를 이용해 테스트를 실행해주는데 나는 물리적인 MySQL 데이터베이스를 연결해서 테스트를 할려고 하여 발생한 문제였다.
내장된 메모리 데이터베이스로 바꾸어 문제를 해결할 수도 있겠지만 MySQL을 사용해서 테스트를 하고 싶었다.
그러면 MySQL 데이터베이스를 연결해서 테스트를 할려면 어떤 설정을 재정의 해야하는지 @AutoConfigureTestDatabase
를 살펴보자.
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
}
- replace()
- embeddedDatabase에 관한 설정
- ANY → 자동 or 수동 상관없이 DataSource 빈을 교체
- AUTO_CONFIGURED → 자동 구성된 경우에만 DataSource 빈 교체
- NONE → DataSource를 교체 하지 않음
- connection()
- embeddedDatabase 를 연결해준다.
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:"));
EmbeddedDatabaseConnection
을 살펴보면 제공하는 DatabaseType이 H2, DERBY, HSQLDB 이 있는걸 확인할 수 있다.
TestDatabaseAutoConfiguration
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
public class TestDatabaseAutoConfiguration {
@Bean
@ConditionalOnProperty(prefix = "spring.test.database", name = "replace", havingValue = "AUTO_CONFIGURED")
@ConditionalOnMissingBean
public DataSource dataSource(Environment environment) {
return new EmbeddedDataSourceFactory(environment).getEmbeddedDatabase();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnProperty(prefix = "spring.test.database", name = "replace", havingValue = "ANY",
matchIfMissing = true)
static EmbeddedDataSourceBeanFactoryPostProcessor embeddedDataSourceBeanFactoryPostProcessor() {
return new EmbeddedDataSourceBeanFactoryPostProcessor();
}
- TestDatabaseAutoConfiguration를 보면
@ConditionalOnProperty
으로 AutoConfigureTestDatabase의 replace() 값에따라 bean을 등록해줍니다. - 기본값은 Replace.ANY 이므로
EmbeddedDataSourceBeanFactoryPostProcessor
bean이 등록됩니다.
EmbeddedDatabase getEmbeddedDatabase() {
EmbeddedDatabaseConnection connection = this.environment.getProperty("spring.test.database.connection",
EmbeddedDatabaseConnection.class, EmbeddedDatabaseConnection.NONE);
if (EmbeddedDatabaseConnection.NONE.equals(connection)) {
connection = EmbeddedDatabaseConnection.get(getClass().getClassLoader());
}
Assert.state(connection != EmbeddedDatabaseConnection.NONE,
"Failed to replace DataSource with an embedded database for tests. If "
+ "you want an embedded database please put a supported one "
+ "on the classpath or tune the replace attribute of @AutoConfigureTestDatabase.");
return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(connection.getType()).build();
}
기존 흐름
AutoConfigureTestDatabase
에서 replace() 값을 설정. 기본값은 ANYTestDatabaseAutoConfiguration
에서 replace() 값이 ANY이므로EmbeddedDataSourceBeanFactoryPostProcessor
를 빈으로 등록getEmbeddedDatabase()
에서 데이터베이스 connection 값을 가져온다.- 현재는 내장된 데이터베이스 H2, DERBY, HSQLDB 중 어느것도 설정이 없으므로 NONE을 반환
getEmbeddedDatabase() 을 통해 설정이 되는데 Debug를 통해 값을 살펴보면
connection이 NONE인것을 확인할 수 있습니다. 그리고 NONE인 경우 에러가 발생하게 됩니다.
에러 해결
그러면 MySQL을 사용하기 위해서는 어떻게 해야할까요??
방법은 간단합니다. AutoConfigureTestDatabase
에서 설정을 EmbeddedDatabase를 사용하지 않게 바꿔줍니다.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class GalleryRepositoryTest {
}
Replace 값을 NONE으로 설정해줍니다. Replace.NONE 일 경우 EmbeddedDatabase를 찾아 설정하지 않고 기존 애플리케이션에서 사용한 DataSource(저의 경우 MySQL)가 등록되게 됩니다.
참고자료
https://kangwoojin.github.io/programing/auto-configure-test-database/
'기타' 카테고리의 다른 글
[Error] kotlin으로 mockito의 Argument matchers 사용시 NullPointerException 발생 (0) | 2023.04.27 |
---|---|
[Intellij] Multiple Selector 단축키(같은 단어 일괄 선택) (0) | 2023.04.12 |
[프로젝트] charlieZip #5 - bindingResult 메시지 Json 전송 (0) | 2021.11.21 |
[프로젝트] charlieZip #4 - Directory 구조 개선 (0) | 2021.10.19 |
[프로젝트] charlieZip #3 - 중복되는 로그인 체크 인터셉트로 구현 (0) | 2021.10.08 |
- Total
- Today
- Yesterday
- Parameterized
- prinicipal
- mockK
- Spring
- trailing comma
- autoconfigure
- mockito-kotlin
- asSequence
- java
- IntelliJ
- GSLB
- AWS INDUSTRY WEEK
- 시나리오 테스트
- ExitStatus
- scenario test
- 클린 아키텍처
- BatchStatus
- meta-data
- test
- assertj
- datasource
- kotlin
- spring data jpa
- Stream
- Collection
- WrongTypeOfReturnValue
- JUnit5
- Mockito
- Spring Batch
- A레코드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |