Spring/Spring

[Spring] @Transactional과 메모리 DB를 활용한 데이터 접근 계층 테스트

2022. 8. 13. 19:10
목차
  1. 테스트 원칙
  2. 트랜잭션과 롤백 전략
  3. 테스트에 직접 트랜잭션 추가
  4. @Transactional을 활용한 트랜잭션 추가
  5. 메모리 DB (임베디드 모드 DB)
  6. 참고

테스트 원칙

  • 테스트에는 두 가지 중요한 원칙이 있다
    • 테스트는 다른 테스트와 격리해야 한다
    • 테스트는 반복해서 실행할 수 있어야 한다
  • 데이터 접근 계층 테스트 시 데이터 롤백을 시켜주지 않으면 테스트 데이터가 계속해서 누적되고, 서로 다른 테스트 간에 의존성을 가지게 되면서 위 두 가지 원칙을 위반하게 된다
  • 테스트가 끝날 때마다 추가된 데이터를 DELETE 해줄 수 있지만, 이 방법 또한 궁극적인 해결책이 아니다
    • 만약 테스트 과정에서 데이터를 이미 추가했는데, 테스트가 실행되는 도중에 예외가 발생하거나 애플리케이션이 종료되어버려서 테스트 종료 시점에 DELETE가 이루어지지 않으면 테스트 데이터가 그대로 남아있게 된다

 

 

트랜잭션과 롤백 전략

  • 트랜잭션을 사용하여 이런 문제를 해결할 수 있다
  • 다음 순서와 같이 각각의 테스트 실행 직전에 트랜잭션을 시작하고, 각각의 테스트 실행 직후에 트랜잭션을 롤백해야 테스트 간에 데이터로 영향을 끼치지 않는다
1. 트랜잭션 시작 
2. 테스트 A 실행 
3. 트랜잭션 롤백

4. 트랜잭션 시작 
5. 테스트 B 실행 
6. 트랜잭션 롤백

 

 

테스트에 직접 트랜잭션 추가

@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 findItems() {
        // ...생략
    }
    
}
  • 다음과 같이 트랜잭션 매니저를 주입하여 트랜잭션을 활성화시킬 수 있다
  • @Transactional을 활용하면 더욱 깔끔하게 코드를 작성할 수 있다

 

 

@Transactional을 활용한 트랜잭션 추가

import org.springframework.transaction.annotation.Transactional;

@Transactional
@SpringBootTest
class ItemRepositoryTest {

    @Autowired
    ItemRepository itemRepository;
    
    @Test
    void findItems() {
        // ...생략
    }
    
}
  • 다음과 같이 테스트 클래스에 @Transactional을 붙여주면 별도의 코드 없이 트랜잭션을 활성화시킬 수 있다
  • @Transactional이 테스트에 있으면 스프링은 테스트를 트랜잭션 안에서 실행하고, 테스트가 끝나면 트랜잭션을 자동으로 롤백시켜 버린다

 

@Transactional이 적용된 테스트 동작 방식

@Test
void findItems() {

    Item item1 = new Item("itemA-1", 10000, 10);
    Item item2 = new Item("itemA-2", 20000, 20);
    Item item3 = new Item("itemB-1", 30000, 30);

    itemRepository.save(item1);
    itemRepository.save(item2);
    itemRepository.save(item3);

    //..검증코드(SELECT SQL) 생략
}

  1. @Transactional이 테스트 메서드나 클래스에 있으면 먼저 트랜잭션을 시작한다.
  2. 테스트 로직을 수행한다. 이때, 테스트가 끝날 때까지 모든 로직은 트랜잭션 안에서 수행된다.
  3. 테스트 실행 중에 INSERT SQL을 사용해서 item1, item2, item3를 데이터베이스에 저장한다.
  4. 검증을 위해서 SELECT SQL로 데이터를 조회한다. 여기서는 앞서 저장한 item1, item2, item3이 조회되었다.
  5. @Transactional이 테스트에 있으면 테스트가 끝날 때 트랜잭션을 강제로 롤백한다.
  6. 롤백에 의해 앞서 데이터베이스에 저장한 item1, item2, item3의 데이터가 제거된다.

 

기타

  • 클래스가 아닌 메서드에 @Transactionl을 붙이면 메서드 레벨에서만 트랜잭션이 동작한다
  • @Commit이나 @Rollback(value = false)를 붙이면 테스트 종료 후 롤백 대신 커밋이 호출된다

 

 

메모리 DB (임베디드 모드 DB)

임베디드 모드

  • 실제 운영 DB가 아닌 메모리DB를 사용해서 데이터 접근 계층에 대한 테스트를 수행할 수 있다.
  • H2 DB는 자바로 개발되어 있고, JVM 안에서 메모리 모드로 동작하는 특별한 기능을 제공하기 때문에 앱을 실행할 때 H2 DB도 해당 JVM 메모리에 포함해서 함께 실행할 수 있다
    • DB를 애플리케이션에 내장해서 함께 실행한다고 해서 임베디드 모드(Embedded mode)라고 한다
    • 애플리케이션이 종료되면 임베디드 모드로 동작하는 H2 DB도 함께 종료되고, 데이터도 모두 사라진다
  • 스프링 부트는 데이터베이스에 대한 별다른 설정이 없으면 메모리 DB를 사용한다
    • 스프링 부트에서 메모리 DB를 설정하는 자세한 방법은 https://docs.spring.io/spring-boot/docs/current/reference/html/data.html#data.sql.datasource.embedded을 참고한다

 

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)
);
  • 메모리 DB는 애플리케이션이 종료될 때 함께 사라지기 때문에 애플리케이션 실행 시점에 DB 테이블도 새로 만들어주어야 한다
  • 스프링 부트는 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 데이터베이스를 초기화하는 기능을 제공한다
  • 이를 위해선 SQL 스크립트를 특정한 경로에 정해진 파일명으로 넣어줘야 한다
    • src/test/resources/schema.sql
    • 자세한 내용은 https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-%20initialization.using-basic-sql-scripts을 참고한다

 

 

참고

스프링 DB 2편

 

저작자표시 비영리 (새창열림)

'Spring > Spring' 카테고리의 다른 글

[Spring] 트랜잭션 AOP 사용 시 주의점 (ft. Spring AOP self-invocation)  (0) 2022.09.01
[Spring] 테스트 코드를 작성할 때 @Transactional을 주의하라  (4) 2022.08.17
[Spring] 트랜잭션 동기화 정리  (0) 2022.08.13
[Spring] 트랜잭션 추상화 정리  (0) 2022.08.08
[Spring] 스프링 DataSource 간단하게 정리  (0) 2022.08.08
  1. 테스트 원칙
  2. 트랜잭션과 롤백 전략
  3. 테스트에 직접 트랜잭션 추가
  4. @Transactional을 활용한 트랜잭션 추가
  5. 메모리 DB (임베디드 모드 DB)
  6. 참고
'Spring/Spring' 카테고리의 다른 글
  • [Spring] 트랜잭션 AOP 사용 시 주의점 (ft. Spring AOP self-invocation)
  • [Spring] 테스트 코드를 작성할 때 @Transactional을 주의하라
  • [Spring] 트랜잭션 동기화 정리
  • [Spring] 트랜잭션 추상화 정리
코택
코택
코택
TaxFree
코택
전체
오늘
어제
  • 분류 전체보기 (369)
    • Spring (29)
      • Spring (18)
      • 스프링 핵심 원리 - 고급편 (11)
    • Spring Batch (4)
    • JPA (4)
    • CS (89)
      • 자료구조 (2)
      • 네트워크 (5)
      • 운영체제 (1)
      • 데이터베이스 (4)
      • SQL (7)
      • 알고리즘 이론 (4)
      • 알고리즘 문제 풀이 (66)
    • 웹 (28)
      • React.js (4)
      • Next.js (1)
      • Node.js (14)
      • FastAPI (4)
      • Django (5)
    • 프로그래밍 언어 (45)
      • Python (5)
      • Java + Kotlin (29)
      • JavaScript + TypeScript (11)
    • 테스트코드 (26)
      • ATDD, 클린 코드 with Spring (4)
      • 이규원의 현실 세상의 TDD: 안정감을 주는 코드.. (20)
    • 인프라 (6)
      • AWS (2)
      • Kubernetes (4)
    • 트러블슈팅 (25)
    • 책 (89)
      • Effective Java (54)
      • Effective Kotlin (14)
      • 도메인 주도 개발 시작하기: DDD 핵심 개념 정.. (11)
      • 웹 프로그래머를 위한 데이터베이스를 지탱하는 기술 (6)
      • 도메인 주도 설계 첫걸음 (4)
    • Git (10)
    • 회고 (5)
    • etc (8)

블로그 메뉴

  • 홈
  • 방명록
  • 관리
  • GitHub
  • LinkedIn

공지사항

  • 스킨 관련

인기 글

태그

  • 그래프 탐색
  • 그래프
  • 백준
  • BOJ
  • 브루트포스
  • dp
  • atdd
  • 깊이 우선 탐색
  • Shortest Path
  • Git
  • fastapi
  • 장고
  • 파이썬
  • http
  • mysql

최근 댓글

최근 글

hELLO · Designed By 정상우.
코택
[Spring] @Transactional과 메모리 DB를 활용한 데이터 접근 계층 테스트
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.