-
스프링 DB 데이터접근 기술 - 테스트Spring-Boot/스프링 DB 2편 - 데이터 접근 기술 2022. 9. 14. 18:41
* @SpringBootTest *
- @SpringBootTest는 @SpringBootApplication 를 찾아서 설정으로 사용한다.
테스트의 원칙
- * 테스트는 다른 테스트와 격리해야 한다. *
- * 테스트는 반복해서 실행할 수 있어야 한다. *
* 트랜잭션과 롤백 전략 *
- 테스트가 끝나고 나서 트랜잭션을 강제로 롤백해버리면 데이터가 깔끔하게 제거된다.
@Autowired PlatformTransactionManager transactionManager; TransactionStatus status; @BeforeEach void beforeEach(){ // 트랜잭션 시작 status = transactionManager.getTransaction(new DefaultTransactionDefinition()); } @AfterEach void afterEach() { //MemoryItemRepository 의 경우 제한적으로 사용 if (itemRepository instanceof MemoryItemRepository) { ((MemoryItemRepository) itemRepository).clearStore(); } // 트랜잭션 롤백 transactionManager.rollback(status); }
- 트랜잭션 관리자는 `PlatformTransactionManager`를 주입 받아서 사용
ㆍ스프링 부트가 자동으로 적절한 트랜잭션 매니저를 스프링 빈으로 등록
- @BeforeEach : 각각의 테스트 케이스를 실행하기 직전에 호출된다.
ㆍ따라서 여기서 트랜잭션을 시작하면 된다.
ㆍ`transactionManager.getTransaction(new DefaultTransactionDefinition()) 로 트랜잭션을 시작한다.
- @AfterEach : 각각의 테스트 케이스가 완료된 직후에 호출
ㆍ따라서 여기서 트랜잭션을 롤백하면 된다.
ㆍ`transactionManager.rollback(status)`로 트랜잭션을 롤백
@Transactional 원리
- 스프링이 제공하는 @Transactional 애노테이션은 로직이 성공적으로 수행되면 커밋되도록 동작
- 그런데 @Transactional 은 테스트에서 사용하면 아주 특별하게 동작
ㆍ테스트를 트랜잭션안에서 실행하고, 테스트가 끝나면 트랜잭션을 자동으로 롤백
* 정리 *
- 테스트가 끝난 후 개발자가 직접 데이터를 삭제하지 않아도 되는 편리함을 제공
- 테스트 실행 중에 데이터를 등록하고 중간에 테스트가 강제로 종료되어도 걱정 없다.
이 경우 트랜잭션을 커밋하지 않기 때문에, 데이터는 자동으로 롤백된다.
(보통 데이터베이스 커넥션이 끊어지면 자동으로 롤백되어 버린다.)
- 트랜잭션 범위 안에서 테스트를 진행하기 때문에 동시에 다른 테스트가 진행되어도 서로 영향을 주지 않는 장점이 있다
- @Transactional 덕분에 아주 편리하게 다음 원칙을 지킬 수 있다.
ㆍ테스트는 다른 테스트와 격리해야 한다
ㆍ테스트는 반보해서 실행할 수 있어야 한다
* 강제로 커밋하기 - @Commit *
- @Transactional 을 테스트에서 사용하면 테스트가 끝나면 바로 롤백되기 때문에 테스트 과정에서 저장한 모든 데이터가 사라진다.
- 데이터베이스에 데이터가 잘 보관되었는지 확인하고 싶을 때 @Commit을 클래스 또는 메서드에 붙이면 테스트 종료 후 롤백 대신 커밋이 호출 된다.
* 임베디드 모드 *
- H2 데이터베이스는 자바로 개발되어 있고, JVM안에서 메모리 모드로 동작하는 특별한 기능을 제공한다.
- 그래서 애플리케이션을 실행할 때 H2데이터베이스도 해당 JVM메모리에 포함해서 함께 실행할 수 있다.
- DB를 애플리케이션에 내장해서 함께 실행한다고 해서 임베디드 모드(Embeded mode)라 한다.
- 물론 애플리케이션이 종료되면 임베디드 모드로 동작하는 H2 데이터베이스도 함께 종료되고, 데이터도 모두 사라짐
- 쉽게 이야기해서 애플리케이션에서 자바 메모리를 함께 사용하는 라이브러리처럼 동작하는 것이다.
@Bean @Profile("test") public DataSource dataSource() { log.info("메모리 데이터베이스 초기화"); DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; }
- dataSource()
ㆍ`jdbc:h2:mem:db` : 이 부분이 중요하다. 데이터소스를 만들때 이렇게 적으면 임베디드 모드(메모리 모드)로
동작하는 H2 데이터베이스를 사용할 수 있다
ㆍ`DB_CLOSE_DELAY=-1` : 임베디드모드에서는 데이터베이스 커넥션 연결이 모두 끊어지면 데이터베이스도
종료되는데, 그것을 방지하는 설정이다
ㆍ이 데이터소스를 사용하면 메모리 DB를 사용할 수 있다.
* 스프링 부트 - 기본 SQL 스크립트를 사용해서 데이터베이스를 초기화하는 기능 *
- 메모리 DB는 애플리케이션이 종료될 때 함께 사라지기 때문에, 애플리케이션 실행 시점에 데이터베이스 테이블도 새로 만들어주어야 한다.
- JDBC나 JdbcTemplate를 직접 사용해서 테이블을 생성하는 DDL을 호출해도 되지만, 너무 불편하다
- 스프링 부트는 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 데이터베이스 초기화하는 기능을 제공한다
- 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) );
스프링 부트와 임베디드 모드
- test properties의 DB 정보 삭제
- 이렇게 별다른 정보가 없으면 스프링 부트는 임베디드 모드로 접근하는 데이터소스(`DataSource`)를 만들어서 제공한다.
- 참고로 로그를 보면 `jdbc:h2:mem` 뒤에 임의의 데이터베이스 이름이 들어가 있다.
- 이것은 혹시라도 여러 데이터소스가 사용될 때 같은 데이터베이스를 사용하면서 발생하는 충돌을 방지하기 위한 스프링 부트가 임의의 이름을 부여한 것이다.
'Spring-Boot > 스프링 DB 2편 - 데이터 접근 기술' 카테고리의 다른 글
스프링 DB 데이터접근 기술 - 스프링데이터 JPA (0) 2022.09.22 스프링 DB 데이터접근 기술 - JPA (0) 2022.09.22 스프링 DB 데이터접근 기술 - MyBatis (0) 2022.09.17 스프링 DB 데이터접근 기술 - 스프링 JdbcTemplate (0) 2022.09.05 스프링 DB 데이터접근 기술 - 시작 (0) 2022.09.01