제육's 휘발성 코딩
article thumbnail
반응형

데이터베이스 연동 테스트

데이터 접근 기술은 실제 데이터베이스에 접근해서 데이터를 잘 저장하고 조회할 수 있는지 확인하는 것이 필요하다.

테스트 단에서 데이터베이스 접근을 위한 별도의 설정을 위해 db2test 라는 이름으로 새로운 스키마를 생성하자.

 

Item 테이블 생성

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)
);
  • 새로운 테이블을 사용하기 때문에 다시 Item 테이블을 생성하자.

application.properties (test)

spring.profiles.active=test
spring.datasource.url=jdbc:h2:tcp://localhost/~/db2test
spring.datasource.username=sa

logging.level.org.springframework.jdbc=debug

 

테스트 - 데이터 롤백

테스트는 다른 테스트와 격리하면서 반복해서 실행할 수 있어야 한다. 테스트가 끝날 때마다 데이터를 DELETE하는 방법을 사용할 수 있지만, 도중에 예외가 발생하거나 애플리케이션이 종료된다면 데이터가 남아있을 수 있다.

이 문제를 해결하는 것이 트랜잭션이다. 테스트가 끝나고 나서 트랜잭션을 롤백하면 데이터가 깔끔히 제거되며, 중간에 실패해서 롤백을 호출하지 못하더라도 트랜잭션을 커밋하지 않았기 때문에 데이터가 반영되지 않는다.

테스트 레벨에서는 테스트 실행 전에 설정인 @BeforeEach 와 실행 후에 동작하는 @AfterEach 라는 편리한 기능을 제공한다.

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

@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);
  }
}
  • 트랜잭션 관리자인 PlatformTransactionManager를 주입 받아서 사용하면, 각 테스트 전에 트랜잭션을 시작하고, 테스트가 끝나면 롤백을 하는 설정을 할 수 있다.

 

테스트 - @Transactional

이전에 작업한 트랜잭션 직접 등록하는 방식을 어노테이션으로 간단하게 사용할 수 있다. 스프링이 제공하는 @Transactional 은 로직이 성공적으로 수행되면 커밋하도록 동작한다.

이 어노테이션을 테스트 코드에서 작성하면 테스트를 트랜잭션 안에서 실행하고, 테스트가 끝나면 자동으로 롤백시켜 버린다.

@SpringBootTest
@Transactional
class ItemRepositoryTest {

  @Autowired
  ItemRepository itemRepository;
}
  • 어노테이션을 클래스 레벨에서 사용하므로 동일하게 실행되는 것을 확인할 수 있다.

 

@Transactional 테스트 레벨 동작 방식

image

  • 트랜잭션을 먼저 시작하고, 자동 커밋 기능을 없앤 후 값을 저장 (자동 커밋이 아니기 때문에 커밋된 상태는 아니고 현재 세션에서만 값을 볼 수 있고, 다른 세션에선 조회 불가인 상황)
  • 값을 조회 후, 테스트가 종료되면 자동으로 트랜잭션 롤백으로 초기화

참고

테스트 케이스의 메서드나 클래스에 @Transactional을 직접 붙여서 사용할 때 만 이렇게 동작한다. 서비스, 리포지토리에 있는 @Transactional도 시작한 트랜잭션에 참여한다. 즉, 테스트에서 시작한 트랜잭션으로 다른 트랜잭션을 전파한다. 이 때 테스트에서 시작한 트랜잭션 범위 안에서 트랜잭션이 실행되고 종료 된다.

테스트 레벨에서 @Transactional을 사용하고 있지만, 강제로 커밋하고 싶은 경우 @Commit 또는 @Rollback(value=false)를 사용하면 테스트 종료 후 롤백 대신 커밋이 호출된다.

 

테스트 - 임베디드 모드

H2 데이터베이스는 자바로 개발되어 있고, JVM안에서 메모리 모드로 동작하는 특별한 기능을 제공한다. 따라서 애플리케이션 실행할 때 H2 데이터베이스도 해당 JVM 메모리에 포함해서 함께 실행할 수 있다. DB를 애플리케이션에 내장해서 함께 실행한다고 해서 임베디드 모드라고 한다.

ItemServiceApplication

@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;
}
  • 다음과 같이 프로필이 "test"인 경우에만 데이터소스를 스프링 빈으로 등록하도록 설정하였다.
  • dataSource()
    • jdbc:h2:mem:db : 데이터소스를 만들 때 임베디드 모드(메모리 모드)로 동작하도록 H2 데이터베이스를 사용할 수 있다.
    • DB_CLOSE_DELAY=-1 : 임베디드모드에선 데이터베이스 커넥션 연결이 끊어지면 데이터베이스도 종료되는데, 그것을 방지하는 설정이다.

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)
);
  • 메모리 디비는 애플리케이션 내부에서 동작하기 때문에 별도의 테이블을 만들어줘야 한다. 이 때 JDBC등을 사용해서 직접 생성할 수 있지만, schema.sql이라는 파일을 경로에 맞춰서 생성하면 애플리케이션 로딩 시점에 데이터베이스를 초기화하는 기능을 제공해준다.

 

테스트 - 스프링 부트 임베디드 모드

스프링부트는 임베디드 데이터베이스에 대한 설정도 기본으로 제공한다.

ItemServiceApplication

/*    @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;
}*/
  • 기존에 빈 등록한 내용을 주석처리 하자.

 

application.properties (테스트)

spring.profiles.active=test
#spring.datasource.url=jdbc:h2:tcp://localhost/~/db2test
#spring.datasource.username=sa
  • 테스트 디렉토리에 있는 application.properties에 데이터소스 관련 설정을 주석처리 하자.

해당 설정을 마치면 자동으로 스프링부트가 임베디드 모드로 접근하는 데이터소스를 만들어서 제공한다.


REFERENCES

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^