본문 바로가기

3.구현/Java or Kotlin

[spring] Spring Framework에서 DB연동 테스트

들어가기

Spring에서 사용하는 테스트 라이브러리와 활용을 살펴보자.

이 글은 spring.io에 Testing[1]에서 DB관련 일부 내용을 정리하였다.

작성자: ospace114@empal.com, http://ospace.tistory.com/

DB 설정

DB 환경설정 위한 2가지 방법있다.

직접 설정

  • Configuration 어노테이션을 사용한 datasource 설정
  • properties 파일을 사용한 datasource 설정
@Configuration
@MapperScan("kr.co.test.foo.repository")
public class RepositoryConfig {
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
          .setType(EmbeddedDatabaseType.H2)
          //.addScript("schema.sql")
          //.addScript("data.sql")
          .build();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
        return factoryBean.getObject();
    }
}

자동 설정

// @SpringBootConfiguration
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"kr.co.test.foo"})
public class RepositoryAutoConfig {
}

DB 설정 properties

test_h2.properties 파일

# spring.datasource.platform=mysql
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./target/data_h2
#spring.datasource.url=jdbc:h2:mem:testdb
#spring.datasource.username=root
#spring.datasource.password=icandoit

#spring.h2.console.enabled=true
#spring.h2.console.path=/h2

#mybatis.mapper-locations=classpath*:mapper/**/*.xml
#mybatis.configuration.map-underscore-to-camel-case=true

test_mysql.properties 파일

spring.datasource.platform=mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shorturl?serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=icandoit

mybatis.mapper-locations=classpath*:mapper/**/*.xml
mybatis.configuration.map-underscore-to-camel-case=true

테스트용 DB 스키마

schema.sql 파일

DROP TABLE IF EXISTS `tb_foo`;
CREATE TABLE `tb_foo` (
  `key` varchar(8) PRIMARY KEY,
  `create_date` timestamp DEFAULT CURRENT_TIMESTAMP
);

data.sql 파일

TRUNCATE TABLE `tb_foo`;
INSERT INTO `tb_foo` (`key`)
VALUES ('a01');

SQL 로딩

테스트 케이스 별로 sql로딩해서 처리할 수 있다.

@Test
@Sql(scripts = {"/import_senior_employees.sql"}, 
  config = @SqlConfig(encoding = "utf-8", transactionMode = TransactionMode.ISOLATED))
public void test1()  {
}

@Test  
@Sql({"/import_senior_employees.sql"})
public void test1()  {
}

@SqlGroup({ @Sql(scripts = "/employees_schema.sql", config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)), @Sql("/import_employees.sql")})
public class TestFoo {
}

테스트 클래스 작성

이 모든 것을 하나의 테스트 실행 class로 작성하면 아래와 같다.

@RunWith(SpringRunner.class) // 스프링 테스트 러너
@SpringBootTest // 스프링 부트 테스트
// @SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"kr.co.test.foo"})
@TestPropertySource(location = "test.properties") // 테스트용 properties 설정 파일 지정
@Sql({"schema.sql", "data.sql"}) // DB용 스키마 와 데이터 쿼리
public class TestFoo {
    //…
}

앞의 RepositoryAutoConfig 클래스가 있다면 생략 가능.
한 패키지에 여러 테스트 클래스를 사용하는 경우 SpringBootConfiguration 충돌이 발생할 수 있기 때문에 RepositoryAutoConfig를 활용하는게 좋음. (SpringBootApplication과 충돌해서 주의가 필요한다)

@RunWith(SpringRunner.class) // 스프링 테스트 러너
@SpringBootTest // 스프링 부트 테스트
// @SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"kr.co.test.foo"})
@TestPropertySource(location = "test.properties") // 테스트용 properties 설정 파일 지정
@Sql({"schema.sql", "data.sql"}) // DB용 스키마 와 데이터 쿼리
public class TestFoo {
    //…
}

만약 DB 테스트 중에 데이터들을 롤백하려면 @Transactional 을 추가함.

@Transactional
public class TestFoo {
    //…
}

테스트코드

DB 설정은 별도로 하지 않고, test_h2.properties파일만 사용한다. RepositoryConfig와 RepositoryAutoConfig은 생성하지 않는다. 만약 생성되어 있다면 test_h2.properties에서 DB관련 설정이 작동하지 않을 수 있다.

@SpringBootTest
@TestPropertySource(locations = "test_h2.properties")
@Sql({"schema_h2.sql", "data.sql"})
public class FooCreatorApplicationTests {
    private static final Logger logger = 
            LoggerFactory.getLogger(FooCreatorApplicationTests.class);

    @Autowired
    private TimerMapper timerMapper;

    @Before
    public void setup() {
        logger.info("begin");
        logger.info("end");
    }

    @After
    public void teardown() {
        logger.info("begin");
        logger.info("end");
    }

    @Test
    public void contextLoads() {
        logger.info("timerMapper[{}]", timerMapper);
        assertNotNull(timerMapper);
        logger.info("time[{}]", timerMapper.getTime());
    }
}

참조

[1] Testing, https://docs.spring.io/spring-framework/reference/testing.html

반응형