본문 바로가기
Spring

Spring JUnit5 Sql script로 테스트 데이터 불러오기

by wadekang 2022. 3. 17.

테스트를 할 때 sql로 미리 데이터를 insert 하고 해당 데이터로 테스트를 진행하고 싶을 경우 다음과 같이 설정하면 된다. 

 

먼저 테스트 폴더에 resources 폴더를 만들어서 applciation.yml (or properties)을 설정해준다. 

spring:
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1
    username: sa
    password:
    driver-class-name: org.h2.Driver

  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        storage-engine: innodb
    hibernate:
      ddl-auto: create-drop
      show-sql: true
      format_sql: true
    defer-datasource-initialization: true

  h2:
    console:
      enabled: true

테스트는 인메모리로 진행하는 게 좋기 때문에 따로 application.yml을 만들어 h2 database 설정을 해주었다. 자신이 사용하는 db에 맞게 설정하면 될 것 같다.

여기서 defer-datasource-initialization을 꼭 해주어야 sql script로 데이터를 로드할 수 있다.

 

설정을 다 해주었으면 resources 폴더 안에 sql script를 생성한 후, 테스트 데이터에 맞게 SQL을 작성한다. 

 

그 후 테스트 코드에서 다음과 같이 설정해 준다.

@SpringBootTest
@Transactional
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TakeClassTest {

    ...

    @Autowired
    DataSource dataSource;

    @BeforeAll
    public void init() {
        try (Connection conn = dataSource.getConnection()) {
            // 자신의 script path 넣어주면 됨
            ScriptUtils.executeSqlScript(conn, new ClassPathResource("/db/h2/data.sql"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    ...
}

@BeforeAll 어노테이션은 최초 테스트 시작 전에 한 번 실행되기 때문에 본래 static method로 선언해야 하고, @Autowired로 주입받은 인스턴스를 사용하지 못한다. 주입받은 인스턴스를 사용하지 못하는 이유는 TestInstance의 Lifecycle이 기본값이 method이기 때문에 TakeClassTest의 인스턴스가 메서드 별로 다시 생성되어 다시 @Autowired 하기 때문이다.

 

@TestInstance 어노테이션을 사용해 TestInstance의 Lifecycle을 PER_CLASS로 바꿔줌으로 @BeforeAll을 static method로 선언하지 않고, 주입받은 인스턴스를 모든 메소드에서 공유 가능하도록 함으로써 DB에서 값을 가져와 메소드에서 공유해 사용할 수 있도록 해 주었다.

 

DB의 데이터를 공유해 사용하면 다음 테스트에서 오류가 발생할 수 있는데, 이를 방지하기 위해 @Transactional 어노테이션을 추가해 주었다. 테스트에서 @Transactional을 사용하면 기본값으로 Rollback이 true이기 때문에 한 테스트를 수행한 후에 데이터가 DB에 커밋되지 않고 롤백된다. 그렇기 때문에 각 메소드 별로 독립적으로 테스트를 수행할 수 있다.

 

 TestInstance의 Lifecycle에 대해 이해가 잘 되지 않는다면 아래의 테스트 코드를 실행해보면 좋을 것 같다.

// @TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class InstanceTest {

    int sum = 1;

    @Test
    void test1() {
        sum += 2;
        assertThat(sum).isEqualTo(3);
    }

    @Test
    void test2() {
        sum += 3;
        assertThat(sum).isEqualTo(4);
    }
}

 

 

위 코드대로 한 번 실행해본 후 @TestInstance의 주석을 풀고 테스트를 실행하면 어느 정도 감이 잡힌다.

 

 

참고

 

댓글