본문 바로가기

Spring

@JdbcTest와 @DataJdbcTest

@JdbcTest와 @DataJdbcTest

 

테스트를 작성함에 있어, 중요한 요소 중 하나는 빠르게 수행되어야 한다는 것이다. (테스트 수행 시간이 길어진다면, 코드를 수정하고 테스트하는 작업을 안 하게 될 수 있다.)

그래서 나는 Persistence Layer 계층의 클래스들을 테스트할 때 @DataJdbcTest, @JdbcTest를 사용하고 있었다. 하지만 해당 어노테이션들의 의미를 정확히 모르고 사용하고 있었다. 그래서 이번 기회에 공부하고 공부한 내용을 공유하고 싶어 글을 작성하게 됐다.

 

@JdbcTest

공식 문서를 살펴보면 다음과 같이 정리할 수 있다.

  • 모든 스프링 빈을 auto-configuration 하지 않고, JDBC 테스트와 관련된 빈들만 auto-configuration 한다.
  • 기본값으로 각각의 테스트는 하나의 트랜잭션이고, 테스트가 끝나면 roll back 된다.
  • 기본값으로 in-memory db를 사용한다.

 

그럼 코드를 통해 어떻게 위에서 말한 것들이 가능해지는 살펴보겠다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(JdbcTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false) //*
@TypeExcludeFilters(JdbcTypeExcludeFilter.class)
@Transactional //*
@AutoConfigureCache
@AutoConfigureJdbc //*
@AutoConfigureTestDatabase //*
@ImportAutoConfiguration //*
public @interface JdbcTest {
  ...
}

 

어떻게 특정 빈들만 SpringContext에 등록될까?

@OverrideAutoConfiuration을 들어가면 다음과 같이 나와있다.

Annotation that can be used to override {@link EnableAutoConfiguration @EnableAutoConfiguration}. Often used in combination with {@link ImportAutoConfiguration @ImportAutoConfiguration} to limit the auto-configuration classes that are loaded.

 

즉, @OverrideAutoConfiguration과 @ImportAutoConfiguration 어노테이션의 조합으로 현재 내 프로젝트의 모든 빈들을 auto-configuration 하는 게 아니라, 특정 빈만 auto-configuration이 가능하도록 해준다.

 

@AutoConfigureJdbc를 통해 Jdbc 관련된 빈들만 Spring Context에 등록된다. 이로 인해 위에서 말한 모든 빈들을 등록하는 게 아니라 Jdbc와 관련된 빈들만 등록된다.

 

 

어떻게 test마다 Trasnaciton이 적용되고, roll back 될 수 있을까?

@Transactional 어노테이션이 각각의 테스트를 하나의 트랜젝션으로 관리되게 해주고, 테스트가 끝나면 roll back 시켜준다.

 

 

어떻게 Test시 in-memory db를 사용할 수 있을까?

@AutoConfigureTestDatabase를 보면 다음과 같이 나와있다.

Annotation that can be applied to a test class to configure a test database to use instead of the application-defined or auto-configured {@link DataSource}. In the case of multiple {@code DataSource} beans, only the {@link Primary @Primary} {@code DataSource} is considered.

 

즉, 해당 어노테이션이 기본적으로 in-memory db를 사용하는 것을 가능하게 해준다. 만약 다른 테스트에서 다른 db를 사용하고 싶으면 해당 어노테이션을 활용하면 될 것이다.

 

@DataJdbcTest

@DataJdbcTest는 @JdbcTest와 무슨 차이가 있을까?

 

공식 문서를 살펴보면, @JdbcTest와 거의 비슷하다. 하지만 다른 점이 하나 있다.

@JdbcTest는 Jdbc 테스트와 관련된 설정들만 auto-configuration 한다고 나와있다. 하지만 @DataJdbcTest의 경우는 Data Jdbc 테스트와 관련된 설정들만 auto-configuration 한다고 나와있다.

 

이 말로는 명확한 차이를 모르겠다. 코드를 살펴보자.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(DataJdbcTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJdbcTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJdbc //*
@AutoConfigureTestDatabase
@ImportAutoConfiguration
public @interface DataJdbcTest {
  ...
}

 

@JdbcTest와의 차이점은 @AutoConfigureDataJdbc이다. 왜 공식문에서 다르게 말했는지 알 것 같다.

 

그럼 Jdbc와 DataJdbc의 차이점이 뭘까?

좀 더 정확하게 말하면 spring-jdbc와 spring-data-jdbc의 차이라고 생각해도 된다.

spring-jdbc는 기존의 plain jdbc를 스프링 프레임워크에서 사용할 수 있도록 추상화한 것이다. 그 예로 @Transactional, JdbcTemplate 모듈이 있다.

반면에 spring-data-jdbc는 spring-jdbc를 추상화한 것이다. 이로 인해 Spring Data CrudRepository를 사용할 수 있다.

 

정리

@JdbcTest, @DataJdbcTest의 차이는 테스트 시 spring-jdbc 관련 빈들을 등록할지, spring-data-jdbc 관련 빈들을 등록할지의 차이다.

나머지 공통점으로는 테스트에 필요한 빈들만 스프링 컨텍스트에 등록, 기본값으로 in-memory를 사용, 각각의 테스트를 하나의 트랜잭션 단위로 그리고 테스트 후 roll back 해주는 기능을 제공한다.

 

Persistence layer와 관련된 test를 할 때는 해당 어노테이션을 활용해 더 빠른 테스트를 만들어보자.

 

Reference

https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/jdbc/JdbcTest.html

https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/data/jdbc/DataJdbcTest.html

https://stackoverflow.com/questions/51923060/spring-jdbc-vs-spring-data-jdbc-and-what-are-they-supporting

'Spring' 카테고리의 다른 글

Spring's STOMP support 파헤치기  (0) 2023.06.02
Spring Websocket Trobleshooting!! (feat. Decorator Pattern)  (0) 2023.05.21
Spring Cloud GateWay의 non-blocking server  (0) 2022.12.31
@SpringBootTest의 비밀!  (0) 2022.12.11
@RequestBody  (0) 2022.06.10