- Spring Batch Test 공식 문서 (한국어 번역)
공식 문서에 나와있는 batch job의 end to end 테스트 예제는 다음과 같습니다.
@SpringBatchTest
@RunWith(SpringRunner.class) // 스프링 JUnit 기능을 사용하겠다는 표시
@ContextConfiguration(classes = SimpleJobConfiguration.class) // ApplicationContext에 설정할 리소스 명시
public class SimpleJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void simple_job_테스트() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);
}
}
Spring Batch 4.1 버전부터 @SpringBatchTest 어노테이션을 사용하면 JobLauncherTestUtils, JobRepositoryTestUtils를 포함한 스프링 배치 테스트 유틸리티를 주입할 수 있습니다.
/**
* @author Mahmoud Ben Hassine
* @since 4.1
* @see JobLauncherTestUtils
* @see JobRepositoryTestUtils
* @see StepScopeTestExecutionListener
* @see JobScopeTestExecutionListener
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@TestExecutionListeners(
listeners = {StepScopeTestExecutionListener.class, JobScopeTestExecutionListener.class},
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
)
public @interface SpringBatchTest {
}
JobLauncherTestUtils 를 살펴보면 단일 Job을 자동 주입받고 있기 때문에 테스트할 Job Configuration을 @ContextConfiguration 어노테이션에 명시해 줍니다.
public class JobLauncherTestUtils {
private SecureRandom secureRandom = new SecureRandom();
/** Logger */
protected final Log logger = LogFactory.getLog(getClass());
private JobLauncher jobLauncher;
private Job job;
private JobRepository jobRepository;
private StepRunner stepRunner;
/**
* The Job instance that can be manipulated (e.g. launched) in this utility.
*
* @param job the {@link AbstractJob} to use
*/
@Autowired
public void setJob(Job job) {
this.job = job;
}
/**
* The {@link JobRepository} to use for creating new {@link JobExecution}
* instances.
*
* @param jobRepository a {@link JobRepository}
*/
@Autowired
public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
...
JobRepositoryTestUtils 에서는 DataSource를 자동 주입받고 있습니다.
public class JobRepositoryTestUtils extends AbstractJdbcBatchMetadataDao implements InitializingBean {
private JobRepository jobRepository;
...
@Autowired
public final void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
...
공식 문서의 예제 코드를 참고하여 테스트 코드를 작성하였습니다.
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SimpleJobConfiguration.class)
public class SimpleJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void simple_job_테스트() throws Exception {
// given
JobParameters jobParameters = new JobParametersBuilder()
.addString("shardNumber", "2")
.addString("version", "RB_0.0.4")
.addString("exeDateTime", "202007241682")
.toJobParameters();
// when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
// then
Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);
}
}
오류가 발생하였습니다.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
원인을 살펴보니 현재 프로젝트에서 dataSource 설정을 위해 생성한 @Configuration 클래스가 많은데 ApplicationContext가 로드되지 않아 JobRepositoryTestUtils 가 dataSource를 주입받지 못해 bean 등록을 못하여 나는 오류였습니다.
해결 방법으로는 세가지가 있습니다.
1. 관련 @Configuration 클래스를 모두 @ContextConfiguration에 명시
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SimpleJobConfiguration.class)
@EnableBatchProcessing // (1) Spring Batch 기능 사용
@EnableConfigurationProperties // (2) @ConfigurationProperties 어노테이션을 사용 중인 @Configuration 클래스가 존재하여 enable 처리
@TestPropertySource(properties = {"db.shard.cnt=4"}) // (3) property 값을 사용하는 @Configuration 클래스가 존재하여 해당 값 셋팅
@ContextConfiguration(classes = {
DataSourceConfiguration.class, DbConfigValidation.class, HikariCpProperties.class, MainJdbcProperties.class, UserJdbcProperties.class
}) // (4) ApplicationContext가 로드 될 dataSource 관련 @Configuration 클래스들
public class SimpleJobTest {
...
}
다른 여러 Job Test를 위해 (1), (2), (3), (4) 을 공통으로 만들어 보았습니다.
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@EnableBatchProcessing
@EnableConfigurationProperties
@TestPropertySource(properties = {"db.shard.cnt=4"})
@ContextConfiguration(classes = { DataSourceConfiguration.class, DbConfigValidation.class, HikariCpProperties.class, MainJdbcProperties.class, UserJdbcProperties.class})
public @interface TestBatchConfiguration {
}
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SimpleJobConfiguration.class) // test할 job configuration 설정
@TestBatchConfiguration //
public class SimpleJobTest { // error!!!
...
}
test할 job configuration 클래스를 따로 뺐더니 단일 Context 밖에 테스트를 할 수 없기 때문에 오류가 났습니다.
다중 @ContextConfigutaion 사용을 하려면 상속을 해야 합니다. (참고)
다음은 완성된 예제 코드입니다.
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@EnableBatchProcessing
@EnableConfigurationProperties
@TestPropertySource(properties = {"db.shard.cnt=4"})
public @interface TestBatchConfiguration {
}
@TestBatchConfiguration //
@ContextConfiguration(classes = { DataSourceConfiguration.class, DbConfigValidation.class, HikariCpProperties.class, MainJdbcProperties.class, UserJdbcProperties.class})
public class BaseJdbcTest {
}
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SimpleJobConfiguration.class)
public class SimpleJobTest extends BaseJdbcTest { // 상속
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void simple_job_테스트() throws Exception {
...
}
}
2. 관련 @Configuration 클래스가 속한 package를 @ComponentScan에 명시
dataSource 관련 @Configuration 클래스가 com.biz.config.db 패키지에 속해있습니다.
@ComponentScan 어노테이션을 이용하여 해당 패키지의 @Configuration 클래스들을 자동으로 IoC 컨테이너에 등록하도록 합니다.
2.1. 커스텀 어노테이션로 생성
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@EnableBatchProcessing
@EnableConfigurationProperties
@TestPropertySource(properties = {"db.shard.cnt=4"})
@ComponentScan(basePackages = "com.biz.config.db")
public @interface TestBatchConfiguration {
}
@SpringBatchTest
@RunWith(SpringRunner.class)
@TestBatchConfiguration //
@ContextConfiguration(classes = SimpleJobConfiguration.class)
public class SimpleJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void simple_job_테스트() throws Exception {
...
}
}
2.2. @Configuration 클래스로 생성
@Configuration
@EnableBatchProcessing
@EnableConfigurationProperties
@TestPropertySource(properties = {"db.shard.cnt=4"})
@ComponentScan(basePackages = "com.biz.config.db")
public class TestBatchConfiguration {
}
@SpringBatchTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SimpleJobConfiguration.class, TestBatchConfiguration.class)
public class SimpleJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void simple_job_테스트() throws Exception {
...
}
}
3. @SpringBootTest 사용
@SpringBatchTest
@SpringBootTest
@RunWith(SpringRunner.class)
public class SimpleJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Autowired
private Job sampleJob;
@BeforeEach
public void setUp() {
jobLauncherTestUtils.setJob(sampleJob);
}
@Test
public void simple_job_테스트() throws Exception {
...
}
}
'spring > spring batch' 카테고리의 다른 글
Spring Batch 5.0 마이그레이션 (0) | 2024.05.23 |
---|---|
[Spring Batch4] batch step에서 processor chaining하는 방법 (0) | 2022.02.04 |
[Spring Batch] org.springframework.dao.EmptyResultDataAccessException: Item 0 of 500 did not update any rows (0) | 2021.11.18 |
[Spring Batch] step 중지/통과 하기 (0) | 2021.10.21 |
댓글