Mockito Spy SystemCommandTasklet在Spring Batch Step中

时间:2014-09-24 17:55:54

标签: spring junit mockito spring-batch

我正在重新考虑我为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());
}

是否有更好的方法可以完成测试,使用正确的参数执行脚本而无需实际运行脚本?

0 个答案:

没有答案