본문 바로가기

웹 개발 (Spring Boot)

@TestPropertySource를 활용해서 테스트 DB 분리하기

   메인 DB(실제 운영 시에 사용하는 DB)와 테스트 DB는 분리되어야 한다. 목적에 따라 사용하는 대상을 구분한다는 측면에서도 그렇고, 메인 DB는 테스트 DB와는 다르게 중요한 데이터들이 포함되어 있을 수 있어 더욱 철저한 격리가 요구되기도 한다. 테스트를 수행하기 전마다 데이터를 완전히 비워야 더욱 원활한 테스트를 수행할 수 있기도 있고, 테스트를 할 때 메인 DB의 데이터를 변경할 수 있다는 문제점을 고려해야 하는 등 여러 이유로 테스트 DB를 따로 운영하는 편이 훨씬 더 편리하다. 

 

   메인 DB와 테스트 DB를 분리하는 건 여러 방법이 있는 것으로 안다. JPA나 Spring Data JPA와 관련하여 제공되는 객체를 사용하는 방법, application.properties를 메인 DB와 테스트 DB 각각에 대해 따로 설정하는 방법 등이 있는 것으로 아는데, 필자가 이번에 제시하려고 하는, 몇 개의 프로퍼티 만을 조작하는 방법은 다음의 경우에 유용하게 적용할 수 있겠다.

 

  1. JPA나 Spring Data JPA에 관련한 기술 스택을 적용하지 않을 때
  2. 테이블의 이름을 제외한 모든 설정을 동일하게 사용하고 싶을 때

   설정은 Spring Boot에서의 초기 설정, 사용하는 DBMS의 종류, 나아가 대상이 되는 스키마(MySQL의 경우)를 포함한다. 이런 조건하에서 유용한 이유는, 보면 알겠지만 테스트를 실행할 때 나머지 설정을 전혀 건들지 않고 특정 프로퍼티(즉, 리포지토리 구현체에 적용되는 테이블 이름값)만 "바꿔치기"하는 식으로 동작하려고 하기 때문이다. 

 

   다음은 오늘의 포스팅에서 핵심이 되는 객체들이다.

1. @Value
2. @TestPropertySource
3. @TestPropertySources

 


 

@Value

 

 

   @Value는 프로퍼티 주입을 위해 사용할 수 있는 어노테이션이다. 주입할 프로퍼티를 등록하는 방법은 여러 가지가 있겠지만, 여기서는 가장 간단한 방법인 application.properties를 활용한 프로퍼티 등록을 수행하겠다. 다음과 같이 해당 파일에 키-값 쌍을 적어주면, Spring Boot는 이를 자동적으로 감지하여 프로퍼티로 등록한다(참고 내용으로, 이렇게 바인딩된 프로퍼티는 ServerProperties라는 객체를 통해 내장 서버 환경을 구성하는 데 사용되며, Spring Boot에서는 디폴트 내장 서버로 Apache Tomcat을 사용한다).

# application.properties
schema.article.companies=company_articles
schema.article.industries=industry_articles
schema.article.mains=article_mains
schema.companies=companies
schema.members=members

 

 

   이렇게 등록된 프로퍼티는 @Value와 프로퍼티 표현식을 사용하여 다음과 같이 특정한 객체의 필드에 주입하는 것이 가능하다.

@Repository
@Primary
public class ArticleMainRepositoryImpl implements ArticleMainRepository {

    @Value("${schema.article.mains}")
    private String CURRENT_SCHEMA;
    
    // ...
}

 


 

@TestPropertySource

 

 

   @TestPropertySource는 테스트 실행을 할 때 프로퍼티를 테스트 환경에 맞출 수 있도록 편의 기능을 제공한다. 예를 들어서 테스트 목적 프로퍼티 추가, 메인 App에서 등록된 프로퍼티 오버라이드, 혹은 나아가 테스트를 위해 따로 구성하여 적용하고자 하는 properties 파일에 대한 경로 지정 등을 수행할 수 있다. 물론 이번 목적을 위해서는 위에서 설명된 두 번째 기능이 필요하며, 일반적인 용법으로는 아래와 같이 테스트 클래스를 수식하는 방식으로 사용할 수 있다.

@TestPropertySource(properties = "schema.article.mains=test_article_mains")
class ManagerArticleMainControllerTest implements ArticleMainTestUtils {

	// ...
}

 

 

   또한 이 어노테이션은 Spring이 제공하는 어노테이션 상속 기능을 활용할 수 있으므로, 가령 다음과 같이 테스트를 위해 구성한 사용자 지정 어노테이션에 이 어노테이션을 properties라는 속성 값과 같이 사용함으로써 일관되고 깔끔한 사용을 보장할 수 있다. 다만 필자 같은 경우 이마저도 복잡해 보여서 @TestPropertySource만을 위한 사용자 지정 어노테이션 하나를 더 만들어서 이를 사용하고 있다. 어쨌든 이런 방식을 통해 기존에 설정하였던 프로퍼티를 간단하게 오버라이드하여, 테스트 환경을 사용자 지정화하는 것이 가능하다.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = {
        "schema.article.companies=test_company_articles",
        "schema.article.industries=test_industry_articles",
        "schema.article.mains=test_article_mains",
        "schema.companies=test_companies",
        "schema.members=test_members"
})
public @interface CustomTestConfig {
}

 


 

@TestPropertySources

 

 

   번외로, @TestPropertySource 여러 개를 하나의 어노테이션으로 묶어 관리하고 싶을 수 있다. 이 때는 @TestPropertySources를 사용하면 된다. 사용법은 다음과 같으며, @TestPropertySource 여러 개를 쉼표로 구분하여 함께 다룸으로써 전혀 어렵지 않게 활용할 수 있다. location은 프로퍼티 파일에 대한 경로를 지정해 줄 수 있는 속성으로, 만약에 테스트에 대한 전체 프로퍼티 구조를 다시 작성하는 상황이라면 이 속성을 적극 사용하면 되겠다.

@TestPropertySources({
    @TestPropertySource(locations = "/test.properties"),
    @TestPropertySource(properties = "schema.article.mains=test_article_mains")
})
public @interface CustomPropertySources {
    // ...
}

 


 

   요약하자면, 다음과 같은 몇 가지 문장으로 귀결될 듯하다.

  1. application.properties를 통해 프로퍼티를 손쉽게 등록할 수 있다.
  2. @Value를 사용하여 이 값들을 꺼내어 사용할 수 있다.
  3. @TestPropertySource를 사용하여 기존의 프로퍼티를 오버라이드할 수 있다.
  4. @TestPropertySources로 여러 @TestPropertySource를 간편하게 다룰 수 있다.

 

   끝!