테스트에서는 데이터베이스를 휘발성으로 사용하는 것이 편리하다. H2 인메모리 데이터베이스를 사용하거나 @Transactional
애노테이션을 사용하는 방법이 있다.
그러나 이 경우 매번 데이터베이스의 스키마나 초기 데이터를 만들어줘야 하는 번거로움이 있는데, 외부 SQL 파일을 통해 테스트가 시작될 때마다 간편하게 데이터베이스를 초기화할 수 있다.
spring:
datasource:
url: jdbc:h2:<url>;INIT=RUNSCRIPT FROM '~/create.sql'
username: sa
애플리케이션 설정(application.yml
)에서 JDBC URL에 스키마 파일의 경로를 추가해준다. (INIT=runscript from '~/init.sql';
)
인메모리 모드(jdbc:h2:mem:
)와 서버 모드(jdbc:h2:tcp://
) 모두 가능하다.
String url = "jdbc:h2:mem:test;INIT=runscript from '~/create.sql'\\;runscript from '~/init.sql'";
자바 또는 properties
파일에서는 세미콜론 이스케이프를 위해 백 슬래시를 두 번 입력해준다(\\;
).
<property name="url" value=
"jdbc:h2:mem:test;INIT=create schema if not exists test\;runscript from '~/sql/init.sql'"
/>
XML 파일에서는 한 번만 입력하면 된다(\;
).
url: jdbc:h2:tcp://localhost/~/testonly;INIT=runscript from '~/init.sql';MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;IGNORECASE=TRUE
홈 디렉토리(~
)에 SQL 파일을 두고 테스트해보았더니 초기화가 잘 되었다.
그런데 버전 관리를 하기 위해서 SQL 파일을 클래스패스(/rc/test/resources
)로 옮겨오고 URL을 변경한 경로에 맞게 (classpath:init.sql
)로 변경했는데 ApplicationContext
를 로드할 수 없다는 오류가 발생했다.
인텔리제이 Project Structure를 확인해봤는데 Test Resources 디렉토리가 클래스패스로 정상적으로 등록되어있는 상태였다.
아무래도 JDBC URL로는 클래스패스가 인식되지 않는 것 같아 다른 방법을 찾았다.
@Slf4j
@Transactional
@SpringBootTest
@Sql(scripts = "classpath:/init.sql")
public class MyBatisPostRepositoryTest {}
테스트 클래스에 위와 같이 @Sql
애노테이션을 사용하면 된다.
참고로 스프링의 @Transactional
은 테스트에서 사용하는 경우 데이터 뿐 아니라 스키마도 테스트 이전 상태로 되돌려준다. 일반적인 트랜잭션 개념에서 DDL은 바로 커밋되므로 롤백이 안 되지만, @Transactional
이 적용된 스프링 테스트에서 @Sql
의 초기화 파일을 사용해 등록한 스키마는 테스트가 종료된 후 삭제된다.