테스트 환경 분리, @Transactional과 임베디드 DB
작성일
테스트 환경을 분리해야 하는 이유
애플리케이션 실행 환경과 테스트 실행 환경을 분리하기 위해 트랜잭션
과 임베디드 데이터베이스
를 사용한다.
실행 환경을 분리하는 이유는 테스트 실행 시 데이터들이 현재의 테스트에 영향을 줄 수 있기 때문이다.
테스트 실행 시 중요한 점은 다음 두가지 이다.
- 테스트는
다른 테스트와 격리
해야 한다. - 테스트는
반복해서 실행
할 수 있어야 한다.
트랜잭션 - @Transactional
테스트가 끝날 때 마다 해당 테스트에서 추가한 데이터를 삭제해야 하는데 이때 도움을 주는 것이 트랜잭션
이다. 테스트가 끝나고 나서 트랜잭션을 강제로 롤백해버리면 데이터가 깔끔하게 제거된다. 테스트를 하면서 데이터를 이미 저장했는데 중간에 테스트가 실패해서 롤백을 호출하지 못해도 트랜잭션을 커밋하지 않았기 때문에 데이터베이스에 해당 데이터가 반영되지 않는다.
스프링은 테스트 데이터 초기화를 위해 트랜잭션을 적용하고 롤백하는 방식을 @Transactional
애노테이션으로 해결해준다.
@Transactional
@SpringBootTest
class ItemRepositoryTest {}
@Transactional 정리
- 테스트가 끝난 후 개발자가 직접 데이터를 삭제하지 않아도 되는 편리함을 제공한다.
- 테스트 실행 중에 데이터를 등록하고 중간에 테스트가 강제로 종료되어도 걱정이 없다. 이 경우 트랜잭션을 커밋하지 않기 때문에, 데이터는 자동으로 롤백된다. (보통 데이터베이스 커넥션이 끊어지면 자동으로 롤백되어 버린다.)
- 트랜잭션 범위 안에서 테스트를 진행하기 때문에 동시에 다른 테스트가 진행되어도 서로 영향을 주지 않는 장점이 있다.
- @Transactional 덕분에 아주 편리하게 다음 원칙을 지킬수 있게 되었다.
- 테스트는 다른 테스트와 격리해야 한다.
- 테스트는 반복해서 실행할 수 있어야 한다.
임베디드 모드
H2 데이터베이스는 자바로 개발되었고 JVM 안에서 메모리 모드로 동작하는 특별한 기능을 제공한다. 그래서 애플리케이션을 실행할 때 H2 데이터베이스도 해당 JVM 메모리에 포함해서 함께 실행할 수 있다. DB를 애플리케이션에 내장해서 실행한다고 해서 임베디드 모드(Embedded mode)
라 한다. 물론 애플리케이션이 종료되면 임베디드 모드로 동작하는 DB도 함께 종료되고 모든 데이터가 사라진다.
스프링 부트는 데이터베이스에 대한 별다른 설정이 없으면 임베디드 데이터베이스를 사용한다.
src/test/resources/application.properties
spring.profiles.active=test
#spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase
#spring.datasource.username=sa
#jdbcTemplate sql log
logging.level.org.springframework.jdbc=debug
이렇게 하면 데이터베이스에 접근하는 모든 설정 정보가 사라지게 된다. 이렇게 별다른 정보가 없으면 스프링 부트는 임베디드 모드로 접근하는 데이터 소스(DataSource)를 만들어서 제공한다.
SQL 스크립트 사용
메모리 DB는 애플리케이션이 종료되면 함께 사라지기 때문에 애플리케이션 실행 시점에 데이터베이스 테이블을 새롭게 만들어야 한다. JDBC나 JdbcTemplate를 사용해서 테이블을 생성해도 되지만 불편하다.
스프링 부트는 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 데이터베이스를 초기화하는 기능을 제공한다.
src/test/resources/schema.sql
drop table if exists item CASCADE;
create table item
(
id bigint generated by default as identity,
item_name varchar(10),
price integer,
quantity integer,
primary key (id)
);
위와 같이 SQL 스크립트를 작성하면 스프링 부트는 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 데이터베이스를 초기화하는 기능을 제공한다.