테스트
테스트 - 데이터베이스 분리
- 테스트 코드는 src/test/resources/application.properties 파일이 설정에서 우선 순위를 갖는다.
- @SpringBootTest 사용 시 @SpringBootApplication을 찾아서 설정으로 사용한다.
- 테스트 시 중요한 것은 다른 환경과 분리해야 한다.
- 가장 간단한 방법은 로컬 DB와 테스트 전용 DB를 별도로 운영하는 것
테스트 - 데이터 롤백
- 테스트에서 매우 중요한 원칙
- 테스트는 다른 테스트와 격리해야 한다.
- 테스트는 반복해서 실행할 수 있어야 한다.
- 이때 필요한 것이 트랜잭션이다.
- 테스트 후 트랜잭션을 통해 롤백을 하면 데이터가 저장되지 않으며, 롤백을 하지 못하더라도 트랜잭션이 커밋을 하지 않았기에 데이터가 DB에 반영되지 않는다.
- 트랜잭션을 커밋하지 않으면 다른 트랜잭션, 세션에서 확인이 불가능한 것일뿐 같은 트랜잭션 내부에서는 데이터가 임시 저장되기 때문에 데이터를 조회하거나 사용할 수 있다.
- ex) 트랜잭션 시작 -> 테스트 A 실행 -> 트랜잭션 롤백 -> 트랜잭션 시작 -> 테스트 B 실행 -> 트랜잭션 롤백
트랜잭션을 통해서 테스트끼리 격리될 수 있고 반복해서 테스트를 실행하더라도 문제가 생기지 않는다.
@SpringBootTest
class ItemRepositoryTest {
@Autowired
ItemRepository itemRepository;
@Autowired
PlatformTransactionManager transactionManager;
TransactionStatus status;
@BeforeEach
void beforeEach() {
//모든 테스트 수행 이전에 트랜잭션 시작
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
}
@AfterEach
void afterEach() {
//각 테스트가 끝난 이후 트랜잭션 롤백
transactionManager.rollback(status);
}
@Test
void save() {...}
@Test
void updateItem() {...}
@Test
void findItems() {...}
}
- 테스트 코드 예제
- 트랜잭션 관리자는 PlatformTransactionManager를 주입 받아서 사용
- 스프링 부트에 의해 자동으로 적절한 트랜잭션 매니저를 스프링 빈으로 등록해준다.
- @BeforeEach로 각 테스트 케이스를 실행하기 전에 getTransaction()으로 트랜잭션을 실행
- @AfterEach로 각 테스트 케이스 완료 직후에 rollback()으로 트랜잭션을 롤백함으로 트랜잭션 실행 전 상태로 복구한다.
- 트랜잭션 관리자는 PlatformTransactionManager를 주입 받아서 사용
- 이 모든 과정을 @Transactional 어노테이션 하나로 해결 가능하다.
테스트 - @Transactional
- @Transactional 사용 시 테스트 데이터 초기화를 위해 트랜잭션을 적용하고 롤백을 쉽게 해결해준다.
- @Transactional 원리
- @Transactional : 로직이 성공적으로 수행되면 커밋하도록 동작한다.
- @Transactional을 테스트에서 사용 시 특별하게 동작한다.
- 테스트에서 사용 시 테스트를 트랜잭션 안에서 실행하고 테스트가 끝나면 트랜잭션을 자동으로 롤백시켜버린다.
- 서비스, 레포지토리에 있는 @Transactional도 테스트에서 시작한 트랜잭션에 참여한다.
=> 테스트에서 트랜잭션을 실행하면 테스트 실행이 종료될 때까지 테스트가 실행하는 모든 코드가 같은 트랜잭션 범위에 들어간다. (= 같은 트랜잭션, 커넥션을 사용한다)
- 테스트 중간에 강제 종료가 되더라도 트랜잭션을 커밋하지 않기 때문에 자동 롤백된다.
- 보통 DB 커넥션이 끊어지면 자동으로 롤백된다.
- @Transactional을 테스트에서 커밋을 해야하는 경우 클래스나 메소드 단위에 @Commit이나 @Rollback(false)를 사용하면 된다.
테스트 - 임베디드 모드 DB
- 테스트 케이스를 위해 별도의 DB를 설치하고 운영하는 것은 번거롭다.
- 임베디드 모드 (=메모리 DB)
- H2 데이터베이스는 자바로 개발되었고 JVM안에서 메모리 모드로 동작하는 기능을 제공한다.
그렇기에 애플리케이션 실행 시 H2 데이터베이스도 JVM 메모리에 포함해서 함께 실행할 수 있다. - DB를 애플리케이션에 내장해서 함께 실행하는 것을 임베디드 모드라고 한다.
- 애플리케이션 종료 시 임베디드 모드로 동작하는 H2 데이터베이스도 함께 종료되고 데이터가 모두 사라진다.
- H2 데이터베이스는 자바로 개발되었고 JVM안에서 메모리 모드로 동작하는 기능을 제공한다.
@Slf4j
@Import(JdbcTemplateV3Config.class)
@SpringBootApplication(scanBasePackages = "hello.itemservice.web")
public class ItemServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ItemServiceApplication.class, args);
}
@Bean
@Profile("local")
public TestDataInit testDataInit(ItemRepository itemRepository) {...}
@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;
}
}
- DB 임베디드 모드를 위한 스프링 애플리케이션 클래스 예제 코드
- @Profile("test")를 통해 프로필이 test인 경우에만 스프링 빈으로 등록
- dataSource()
- jdbc:h2:mem:db : 임베디드 모드로 동작하는 H2 데이터베이스를 사용하기 위한 코드
- DB_CLOSE_DELAY=-1 : 임베디드 모드에서 DB 커넥션이 모두 끊어지는 경우 DB도 종료되는데 그걸 방지하는 설정
- 해당 데이터소스 사용 시 임베디드 모드 DB(메모리 DB)를 사용할 수 있다.
- 메모리 DB의 경우 애플리케이션 종료될 때 모두 사라지기에 실행 시점에 DB 테이블도 새로 생성해줘야 한다.
- JDBC나 JdbcTemplate으로 테이블 생성 DDL을 호출해도 되지만 불편하다.
- 스프링 부트에서 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 DB를 초기화하는 기능을 제공한다.
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 스크립트 사용 방법
- 테스트 케이스에서 사용하기 위해서 src/test/resoureces/schema.sql 생성
- 위치, 파일명 모두 일치해야한다.
- schema.sql 파일에 예제와 같이 테이블 생성 DDL SQL 스크립트 작성
- 애플리케이션 로딩 시점에 해당 SQL 스크립트를 통해서 DB를 초기화한다.
- 테스트 케이스에서 사용하기 위해서 src/test/resoureces/schema.sql 생성
테스트 - 스프링 부트와 임베디드 모드
- 스프링 부트에서 임베디드 모드 DB에 대한 설정도 제공해준다.
- DB에 대한 별다른 설정이 없는 경우 임베디드 모드 DB를 사용한다.
- 데이터소스 DB 정보, application.properties의 DB 설정 정보 등... 모든 설정 정보가 없는 경우 스프링 부트는 임베디드 모드로 접근하는 데이터소스를 만들어서 제공한다.
정리
- 테스트에서 매우 중요한 원칙
- 테스트는 다른 테스트와 격리해야 한다.
- 테스트는 반복해서 실행할 수 있어야 한다.
=> 트랜잭션을 사용하면 2가지 원칙을 모두 지킬 수 있다.
- @Transactional : 로직이 성공적으로 수행되면 커밋하도록 동작한다.
- @Transactional을 테스트에서 사용 시 특별하게 동작한다.
- 테스트에서 사용 시 테스트를 트랜잭션 안에서 실행하고 테스트가 끝나면 트랜잭션을 자동으로 롤백시켜버린다.
- 커밋을 해야하는 경우 @Commit, @Rollback(false)를 사용하면 된다.
- @Transactional을 테스트에서 사용 시 특별하게 동작한다.
- 테스트 시 환경 분리를 위해 별도의 테스트 전용 DB를 만들기보다 임베디드 모드 DB를 사용하는 것이 편하다.
- 임베디드 모드 (메모리 DB) : DB를 애플리케이션에 내장해서 함께 실행하는 것으로 애플리케이션 종료 시 임베디드 모드로 동작하는 DB도 함께 종료되고 데이터가 모두 사라진다.
- 임베디드 모드의 경우 애플리케이션 종료될 때 모두 사라지기에 실행 시점에 DB 테이블도 새로 생성해줘야 하는데 스프링 부트가 제공하는 SQL 스크립트를 사용하면 된다.
- 스프링 부트에서 제공하는 SQL 스크립트 사용 방법
- 테스트 케이스에서 사용하기 위해서 src/test/resoureces/schema.sql 생성
- 위치, 파일명 모두 일치해야한다.
- schema.sql 파일에 테이블 생성 DDL과 같이 SQL 스크립트 작성한다.
- 애플리케이션 로딩 시점에 해당 SQL 스크립트를 통해서 DB를 초기화한다.
- 테스트 케이스에서 사용하기 위해서 src/test/resoureces/schema.sql 생성
- 데이터소스 DB 정보, application.properties의 DB 설정 정보 등과 같이 DB에 대한 별다른 설정이 없는 경우 스프링 부트는 임베디드 모드 DB를 사용한다.
출처 : [인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술]
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard
스프링 DB 2편 - 데이터 접근 활용 기술 강의 | 김영한 - 인프런
김영한 | 백엔드 개발에 필요한 DB 데이터 접근 기술을 활용하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 백엔드
www.inflearn.com
'Spring > [인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술]' 카테고리의 다른 글
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - 스프링 데이터 JPA (0) | 2024.11.26 |
---|---|
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - JPA (1) | 2024.11.23 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - MyBatis (1) | 2024.11.21 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - 스프링 JdbcTemplate (1) | 2024.11.21 |
[인프런 김영한 스프링 DB 2편 - 데이터 접근 활용 기술] 데이터 접근 기술 - 시작 (4) | 2024.11.19 |