我正在重新考虑我为Spring Batch作业继承的一个麻烦的测试,该作业调用外部脚本来执行任务。测试的原始版本用简单的移动文件脚本替换真实脚本并启动作业,然后调用该脚本并测试文件是否正确移动(用于验证脚本是否使用正确的参数调用)。 / p>
我对新版本的目标是消除为此测试调用真实脚本的需要,而是存根和验证用于调用脚本的tasklet的执行方法,依靠Mockito的验证来确保正确的参数使用。
作业的配置如下:
<flow id="job-flow">
<step id="preprocess" parent="preprocess-base" next="process">
<tasklet>
<beans:bean class="com.company.project.main.package.PreprocessTasklet">
<beans:property name="doMove" value="false" />
</beans:bean>
</tasklet>
</step>
<step id="process" next="postprocess">
<tasklet ref="commandTasklet" />
</step>
<step id="postprocess" parent="postprocess-base" />
</flow>
<bean id="commandTasklet" class="org.springframework.batch.core.step.tasklet.SystemCommandTasklet" scope="step">
<property name="command" value="${a.dir}/job_script.sh" />
<property name="environmentParams" value="working_dir=#{jobExecutionContext['job.dir']}" />
<property name="workingDirectory" value="${b.dir}" />
<property name="timeout" value="3600000"/>
</bean>
<batch:job id="run-my-script" parent="base-job" incrementer="defaultIncrementer">
<batch:flow id="script-job" parent="job-flow" />
</batch:job>
为了防止commandTasklet调用实际的shell脚本,我使用BeanPostProcessor将其替换为间谍并存根执行方法。
public class SpiedCommandTaskletPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (SystemCommandTasklet.class.isAssignableFrom(bean.getClass())) {
SystemCommandTasklet spiedTasklet = Mockito.spy((SystemCommandTasklet) bean);
try {
Mockito.doReturn(RepeatStatus.FINISHED).when(spiedTasklet)
.execute(Mockito.any(StepContribution.class), Mockito.any(ChunkContext.class));
} catch (Exception e) {
e.printStackTrace();
}
bean = spiedTasklet;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
测试配置:
<bean class="com.company.test.package.postprocessor.SpiedCommandTaskletPostProcessor" />
这部分就像一个魅力。然而,这给我留下了两个问题:首先,到PostProcessor运行时,属性(即我试图验证的SystemCommandTasklet的参数)已经可能已经设置好了;我甚至可以使用Mockito.verify(...)检查所需的值吗? 其次,由于SystemCommandTasklet是步进式的,我不能在我的测试中使用autowire来获取它,并且尝试在ApplicationContext中查找它只是创建一个新的(和实际的)Tasklet实例。步。如何在JUnit测试的上下文中访问这样的步骤范围的tasklet?
@Test
public void testLaunch() throws Exception {
JobExecution jobExecution = getJobLauncher().launchJob(jobParms);
//Mockito.verify(spiedTasklet).execute(Mockito.any(StepContribution.class), Mockito.any(ChunkContext.class)); spiedTasklet not wired to anything. :(
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
是否有更好的方法可以完成测试,使用正确的参数执行脚本而无需实际运行脚本?