【发布时间】:2021-06-20 11:52:39
【问题描述】:
我有一个 Spring 批处理项目。目标是对 Spring Job 中存在的各个步骤执行集成测试。
我正在使用 JobLauncherTestUtils 来启动该步骤。但是,当此实用程序启动这些步骤时,它会在单独的线程中运行它。线程完成执行后,应该为jobExecution.getStepExecutions() 分配一些值。
问题: 出于某种原因,甚至在线程完成执行之前,测试进入下一行List<StepExecution> actualStepExecutions = new ArrayList<>(jobExecution.getStepExecutions()),其中jobExecution.getStepExecutions() 当前为空,因此测试失败并显示@987654324 @ 和 Index 0 out of bounds for length 0 - 标记在下面的测试类中。
问题:有什么优雅的方法可以等待 Step 执行 THREAD 完成,然后进入测试中的下一行进行验证?
代码:
集成测试类:
@Slf4j
@SpringBatchTest
@SpringBootTest
@ActiveProfiles({"test", "master"})
@ContextConfiguration(classes = {InhouseClass3.class, InhouseClass1.class, InhouseClass2.class})
public class BatchJobIntegrationTest {
private static final String Param1 = "someParam";
@Autowired
@Qualifier("hikariDatasource")
DataSource hikariDatasource;
@Autowired
Job BatchJob;
@Autowired
JobLauncher jobLauncher;
JobExecution jobExecution;
@Autowired
CreateDirectoryTasklet createDirectoryTasklet;
JobParameters jobParameters;
JobLauncherTestUtils jobLauncherTestUtils;
@BeforeEach
void setUp() {
String startTimestamp = Timestamp.from(Instant.now()).toString();
jobParameters = new JobParametersBuilder()
.addString(Param1, startTimestamp)
.toJobParameters();
jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJob(BatchJob);
jobLauncherTestUtils.setJobLauncher(jobLauncher);
}
@SneakyThrows
@Test
void TaskletToTest_Test() {
jobExecution = jobLauncherTestUtils.launchStep("loadTaskletToTest", jobParameters);
List<StepExecution> actualStepExecutions = new ArrayList<>(jobExecution.getStepExecutions());
// ERROR: jobExecution.getStepExecutions() is NULL.
ExitStatus actualJobExitStatus = actualStepExecutions.get(0).getExitStatus();
// ERROR: Index 0 out of bounds for length 0
assertEquals("loadGdxClaims", actualStepExecutions.get(0).getStepName());
assertEquals(ExitStatus.COMPLETED, actualJobExitStatus);
}
@SneakyThrows
@Test
// This is my workaround to make my above test run.
// I added a sleep for 2 seconds. But this doesn't look like an ideal way, coz what
// if the launchstep thread running the tasklet took more than 2 seconds?
void loadGDXClaimTaskletTest_Working_() {
jobExecution = jobLauncherTestUtils.launchStep("createDirectory", jobParameters);
boolean counter = true;
while(counter) {
if (jobExecution.getStepExecutions().size()!=0 ) {
List<StepExecution> actualStepExecutions = new ArrayList<>(jobExecution.getStepExecutions());
ExitStatus actualJobExitStatus = actualStepExecutions.get(0).getExitStatus();
log.info("------- step executions : {}", actualStepExecutions);
assertEquals("createDirectory", actualStepExecutions.get(0).getStepName());
assertEquals(ExitStatus.COMPLETED, actualJobExitStatus);
counter = false;
} else {
TimeUnit.SECONDS.sleep(2);
}
}
}
}
Tasklet 测试步骤:
@Slf4j
@Component
public class TaskletToTest implements Tasklet {
private final InhouseService inhouseService;
public TaskletToTest(InhouseService inhouseService) {
this.inhouseService = inhouseService;
}
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws InterruptedException, IllegalJobNameException, JSchException, IOException {
log.info("TaskletToTest before");
inhouseService.retry();
log.info("TaskletToTest after");
return RepeatStatus.FINISHED;
}
}
包含需要测试的步骤列表的批处理作业:
@Slf4j
@Profile("master")
@Configuration
public class MasterConfig extends DefaultBatchConfigurer {
@Bean(name = "BatchJob")
public Job remoteChunkingJob(TaskletStep someOtherTasklet,
TaskletStep loadTaskletToTest,
JobExecutionListener jobExecutionListener) {
return this.jobBuilderFactory.get("extract gdx load")
.incrementer(new RunIdIncrementer())
.listener(jobExecutionListener)
.start(someOtherTasklet)
.next(loadTaskletToTest)
.build();
}
@Bean
TaskletStep loadTaskletToTest(TaskletToTest taskletToTest) {
return this.stepBuilderFactory.get("loadTaskletToTest").tasklet(taskletToTest).build();
}
}
【问题讨论】:
标签: java spring spring-boot spring-batch