지금 프로젝트에 세팅에 맞게만 설명하려고 한다.
먼저 기존의 SuccessStateJobTest.java
파일을 가지고 테스트 코드를 작성하고자 한다.
@ExtendWith(SpringExtension.class) //(0) Spring framework에 junit test를 확장하여 실행하도록 선언
@SpringBatchTest //(1) batch에 필요한 jobLauncherTestUtils, jobRepositoryTestUtils 등의 DI 적용
@SpringBootTest(classes = {TestBatchConfig.class, SuccessStateJob.class, PayRepository.class}) //(2) Spring을 시작시키며 Test를 실행하는데 classes 옵션으로 해당 테스트가 진행될때 applicationContext에 등록할 class들을 정의함. > 여기에 작성하지 않으면 테스트 실행시 DI가 되지 않아 class를 찾을 수 없다고 나옴
class SuccessStateJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils; //(3) batch test용 library
@Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils; //(4) 3과 동일
@Autowired
private PayRepository payRepository; //(5) 개인적으로 정의한 repository
@Test
void 테스트1() throws Exception{
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
}
@Test
void 같은조건을읽고_업데이트() throws Exception{
//given
for(long i=0; i<50; i++){
payRepository.save(new Pay(1000L, "테스트상품",LocalDateTime.now().toString(),"false")); //(6) 상품 50개 등록
}
//when
JobExecution jobExecution = jobLauncherTestUtils.launchJob(); //(7) job 실행
//then
assertThat(payRepository.findAllByState().size()).isEqualTo(54); //(8) 결과 확인
}
}
TestBatchConfig.class
는 직접 batch에 대한 설정파일로 사용자가 따로 정의해주어야한다. 글 밑에서 작성할 예정@SpringBootTest
를 통해 따로 선언해놨기 때문에 선언 해놓은 여러 Job중에 내가 포함시켜둔 job class만 실행됨. 만약 포함시켜두지 않거나 여러 job을 동시에 선언해두면 여러 job이 bean으로 등록되어 찾을 수 없다고 나옴.@Configuration
@EnableAutoConfiguration
@EnableBatchProcessing //batch 실행시 필요한 DI
public class TestBatchConfig {
}
위에서 테스트에 포함시킨 TestBatchConfig.class
test config 파일은 위와 같이 선언된다. 이전에는 JobLauncherTestUtils
를 사용하기 위해 bean으로 등록해주는 코드가 필요했으나 @SpringBatchTest
어노테이션을 통해 모두 실행해주므로 Batch 실행에 필요한 설정만 해주면 된다.
jpa로 작성해서 사용해도 좋겠지만... 프로젝트 특성상 jdbc로 작성해야할 경우가 있다. jpa로 작성하는 방법은 향로님 batch 가이드만 따라가도 충분히 할수 있기 때문에 jdbc로 작성하는 방법을 적어두려고 한다.
@Repository
@RequiredArgsConstructor
public class PayRepository {
private final JdbcTemplate jdbc;
public List<Pay> findAll(){
String sql = "select * from pay";
return jdbc.query(sql, rowMapper);
}
public List<Pay> findAllByState(){
String sql = "select * from pay where success_state = 'true'";
return jdbc.query(sql, rowMapper);
}
public int save(Pay pay){
return jdbc.update("insert into pay (amount, tx_name, tx_date_time, success_state) values (?,?,?,?)", pay.getAmount(), pay.getTxName(), pay.getTxDateTime(), pay.getSuccessState());
}
static RowMapper<Pay> rowMapper = (rs, rowNum) -> new Pay(
rs.getLong("id"),
rs.getLong("amount"),
rs.getString("tx_name"),
rs.getString("tx_date_time"),
rs.getString("success_state")
);
}
jdbc는 JdbcTemplate
을 주입받아서 사용하면 위와 같이 간편하게 사용이 가능하다. 여기서 jpa나 mybatis를 사용하면 자동으로 dao나 entity에 맞춰서 객체로 변환해주던 작업을 우리가 직접 해줘야한다.
그래서 RowMapper를 통해 각 컬럼 값을 우리가 선언한 객체에 맞게 값을 넣어주면 생성자를 통해 객체를 생성한다.
위 findAll()
, findBy**()
, save()
정도의 예제면 충분히 활용해서 다른 코드를 짤 수 있을것이다.
직접적으로 job에서 실행되는 코드는 아니고 테스트를 위한 코드이므로 테스트 코드를 작성하지 않을 거라면 따로 작성할 필요는 없다.
batch는 따로 DB에 transaction을 통해 테스트만하고 데이터를 날려버릴 수 없다. 이 점을 기억하고 테스트할때 잘 작성하자!