프로그래밍/JPA, Database

H2로 SpringBoot 테스트 도중 SQL이 실행되지 않는 경우 대응법

카프카뮈 2021. 10. 8. 20:44

이 글은 다음 상황에 대처한 경험을 작성한 글이다.

  • MySQL, PostgreDB 등에서 사용하던 SQL이 H2 DB에서 실행되지 않는 경우를 확인한다.
  • H2 모드를 조정하여 테스트 환경 등에서 쿼리가 정상 실행되도록 한다.

 


여러 환경에서의 DB 운영

현재 졸업 프로젝트를 진행하면서, 아래처럼 DB 환경을 나눠 구축하고 있다.

  • application.yml에서 여러 yaml 파일을 import하여 관리한다.
  • application-prod.yml에서 운영서버 실행 환경을 설정한다.
    • DB는 MariaDB를 사용하며, flyway를 사용한다.
  • application-local.yml에서 로컬 실행 환경을 설정한다.
    • DB는 MySQL을 사용하며, flyway를 사용한다.
  • application-test.yml에서 테스트 실행 환경을 설정한다.
    • DB는 H2 DB를 사용하며, flyway 사용 없이 jpa의 ddl-auto 기능을 활용하여 ddl을 직접 생성한다.

MySQL과 MariaDB의 SQL 호환이 가능하므로, 로컬 환경에서도 실제 운영 환경처럼 운영해보는데 목적을 두고 있다.

다만 나는 테스트 환경에서는 다음의 이유로 MySQL을 사용하지 않는다.

  • 테스트 때마다 테이블을 지우고 다시 생성해야 하는데, 이를 위해 데이터베이스를 운영하는 것이 비효율적이다.
  • 테스트의 속도가 느려질 수 있다.
  • 만약 로컬 DB가 바뀌면, 테스트 DB도 함께 바꿔야 한다. 즉, 의존성이 크다.

그에 비해, H2 Database는 다음의 이점을 가진다.

  • 매우 빠른 속도를 가진다.
  • 적은 용량으로 운영할 수 있다.
  • 인메모리 데이터베이스이므로, 외부의 요인과 관계없이 테스트할 수 있다.
  • 다른 DB와의 호환성이 좋다.

네이티브 쿼리 사용에 따른 문제

그런데, H2 Database를 사용하면서 한 가지 문제가 생겼다.

아래는 전기차 충전소 정보를 저장하는 Spring Batch 코드의 일부분이다.

 private ItemWriter<Station> stationWriter() {
    JdbcBatchItemWriter<Station> itemWriter = new JdbcBatchItemWriterBuilder<Station>()
            .dataSource(dataSource)
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql("replace into station(station_id, station_name, address, location, latitude, longitude, call_number, use_time) " +
                    "values(:stationId, :stationName, :address, :location, :latitude, :longitude, :callNumber, :useTime) ")
            .build();

    itemWriter.afterPropertiesSet();

    return itemWriter;
}

이 코드를 테스트해보니, BadSqlGrammerException 예외가 발생했다.

왜 그럴까? 이유는 간단하다. replace into 구문이 h2에서 지원되지 않기 때문이다.

이처럼 MySQL 등에서 지원하더라도 H2 Database에서 지원하지 않는 구문이 종종 있다.

그렇다면 어떻게 해야할까? 그렇다고 테스트를 위해 메인 코드를 바꾸는 것은 주객전도 아닐까?

H2 Mode 설정

다행히 H2에서는 호환성 모드를 제공한다.

호환성 모드는 Oracle, MySQL, PostgreSQL에 대해 제공된다.

사용법은 아래와 같다: yaml 파일 혹은 properties 파일에 가서 다음 값을 수정해준다.

(위의 예에서는 application-test.yml을 수정한다.)

spring:
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MYSQL

위의 MODE 값을 원하는 값으로 설정해주면, 해당 데이터베이스의 네이티브 쿼리와 호환이 보장된다.

해당 코드를 수정한 후, 테스트 코드도 잘 작동되는 것을 확인할 수 있었다.


결론: 테스트는 H2로!

앞서 H2 데이터베이스로 테스트할 때의 여러 장점에 대해 언급했다.

물론 인메모리로 그때그때 재생성하고, 가벼운 용량으로 쓸 수 있는것이 큰 장점이다.

하지만 그뿐 아니라, 다양한 로컬/운영 DB와 호환이 보장되는 것 역시 큰 장점이다.

이로 인해서 운영 환경에서의 DB Migration 등이 일어나더라도, 테스트의 결과에 영향을 주지 않기 때문이다.

 

테스트 코드를 작성하며 늘 고민이 많다.

특히 환경 설정에 대해 고민이 많았는데, 이번엔 잘 해결해서 그나마 다행이었다.

혹시 같은 오류를 겪고 있으시다면 도움 많이 되시길.

 

누락된 내용이나 잘못된 내용이 있다면 댓글 부탁드립니다 :)

반응형