Jdbc 테스트 환경 구성

은찬·2023년 10월 26일
1

Java, Spring

목록 보기
4/7

Jdbc Repository 단위 테스트를 위한 환경 구성

단위 테스트의 환경

단위 테스트는 해당 컴포넌트에 대해서만 진행하는 테스트이며 해당 컴포넌트에 있는 코드들만 테스트하면 된다.

그래서 단위 테스트를 할 때 해당 컴포넌트에서 필요한 환경만 구성해야한다. 즉 Application Context 에 모든 Bean 을 띄워주는 @SpringBootTest 는 반드시 지양해야한다.

@SpringBootTest 는 말 그대로 SpringBoot 의 환경을 제공한다. 모든 Bean 을 띄우고 SpringBoot 의 기능을 모두 제공한다. 테스트 할 때는 편할 수 있지만, 굉장히 느리다는 치명적인 단점이 있다.

그래서 각 상황에 맞게 환경을 컴팩트하게 구성해야한다.

@SpringJunitConfig

@SpringJunitConfig 이 만드려는 테스트 환경의 주축이라고 할 수 있다.

@SpringJunitConfig 는 아래와 같이 구성돼 있다.

@ExtendWith(SpringExtension.class)
@ContextConfiguration
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SpringJUnitConfig 

여기서 눈여겨 볼 것은 @ExtendWith(SpringExtension.class)@ContextConfiguration 두개다.

@ExtendWith(SpringExtension.class)

이 어노테이션은 JUnit 5 테스트 라이프사이클에 맞춰서 Spring Application Context 를 만들고 없애주며 테스트 환경에 Spring 환경을 입혀준다.

@ContextConfiguration

이 어노테이션은 스프링 테스트 환경에서 테스트에 필요한 스프링 빈들을 설정할 수 있게 해준다.

DataSource 등록

Jdbc 를 사용하려면 DataSource 가 있어야한다.

그래서 아래처럼 DataSource 를 Bean 으로 등록한다

@SpringJUnitConfig
public class DataSourceTestSupport {

	@TestConfiguration
	static class DataSourceConfig {

		@Value("${spring.datasource.url}")
		private String url;
		@Value("${spring.datasource.driver-class-name}")
		private String driverClasName;
		@Value("${spring.datasource.username}")
		private String username;
		@Value("${spring.datasource.password}")
		private String password;

		@Bean
		public DataSource dataSource() {
			DataSource dataSource = DataSourceBuilder.create()
				.url(url)
				.driverClassName(driverClasName)
				.username(username)
				.password(password)
				.type(HikariDataSource.class)
				.build();

			JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
			jdbcTemplate.execute(SqlFixture.DDL);

			return dataSource;
		}
	}
}

먼저 이 코드의 사용법부터 보자면 간단하게 DataSourceTestSupport 클래스를 상속하면 된다.

그러면 @SpringJUnitConfig 를 통해서 Spring Application Context 환경을 제공받고 등록한 Bean 을 사용할 수 있다.

근데 위 코드에는 해결해야할 문제가 두 가지 있다.

첫 번째는 @Value 어노테이션의 적용이 안된다.

두 번째는 트랜잭션을 적용해야한다(각 테스트 후에 롤백하기 위함)

Property 구성

@SpringJUnitConfig 어노테이션은 Spring Application Context 환경을 제공하지만 빈 깡통이기 때문에 Spring Boot 가 해주는 모든 기능을 제공하지 않는다.

그래서 Property 파일 소스가 포함되지 않아서 @Value 어노테이션이 적용이 되지 않는다.

그래서 직접해줘야 하는데, @TestPropertySource("classpath:application.properties") 이 어노테이션을 추가해서 직접 프로퍼티 파일을 등록해줘야한다.

트랜잭션 적용

Spring Boot 에서는 별도의 설정을 하지 않아도 @Transactional 어노테이션 하나로 간단하게 트랜잭션 기능을 제공받을 수 있다.

하지만 여기선 Spring Boot 의 기능을 제공받지 않기 때문에 이 또한 직접 해줘야한다.

Spring Boot 는 @EnableTransactionManagement 를 통해서 트랜잭션을 제공한다.

슬프게도 @SpringJUnitConfig 에서는 @EnableTransactionManagement 마저 적용되지 않는다.

그래서 결국 트랜잭션을 직접 Bean 으로 등록해야한다

방법은 간단하다

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
	return new DataSourceTransactionManager(dataSource);
}

이렇게 DataSourceTransactionManagerBean 으로 등록하면 된다. 물론 이걸 사용하려면 위에서 DataSource 에 대한 Bean 을 등록해줘야한다

최종 코드

@SpringJUnitConfig
@Transactional
@TestPropertySource("classpath:application.properties")
public abstract class DataSourceTestSupport {

	@TestConfiguration
	static class DataSourceConfig {

		@Value("${spring.datasource.url}")
		private String url;
		@Value("${spring.datasource.driver-class-name}")
		private String driverClasName;
		@Value("${spring.datasource.username}")
		private String username;
		@Value("${spring.datasource.password}")
		private String password;

		@Bean
		public DataSource dataSource() {
			DataSource dataSource = DataSourceBuilder.create()
				.url(url)
				.driverClassName(driverClasName)
				.username(username)
				.password(password)
				.type(HikariDataSource.class)
				.build();

			JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
			jdbcTemplate.execute(SqlFixture.DDL);

			return dataSource;
		}

		@Bean
		public PlatformTransactionManager transactionManager(DataSource dataSource) {
			return new DataSourceTransactionManager(dataSource);
		}
	}
}

위 처럼 구성하면 DataSource 를 주입받아 사용할 수 있고 트랜잭션까지 제공받을 수 있다.

profile
`강한` 백엔드 개발자라고 해두겠습니다

0개의 댓글