针对多个作业的Spring Batch JUnit测试

时间:2015-12-11 06:05:19

标签: spring spring-batch

我在一个上下文文件中配置了两个作业

<batch:job id="JobA" restartable="true">
        <batch:step id="abc">
            <batch:tasklet >
                <batch:chunk reader="reader" writer="writer" processor="processor"  />
            </batch:tasklet>
      </batch:step>

    </batch:job>

<batch:job id="JobB" restartable="true">
        <batch:step id="abc">
            <batch:tasklet >
                <batch:chunk reader="reader" writer="writer" processor="processor"  />
            </batch:tasklet>
      </batch:step>

    </batch:job>

当我使用JobLauncherTestUtils对JobA进行单元测试并测试作业启动时,它会抛出一个例外

No unique bean of type [org.springframework.batch.core.Job;] is defined: expected single matching bean but found 2: [JobA, JobB]

我尝试使用@Qualifier进行autowire仍然是同样的事情。我在哪里做错了

编辑

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:META-INF/spring/batch-test-context.xml" })
public class TestJob {

    @Autowired
    private JobExplorer jobExplorer;

    @Autowired
    @Qualifier("JobA")
    private Job JobA;


    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;


    @Test
    public void testJob() throws Exception {
        JobParameters jobParameters = getNextJobParameters(getJobParameters());
        assertEquals(BatchStatus.COMPLETED, jobLauncherTestUtils.getJobLauncher().run(JobA, jobParameters));
    }


    private JobParameters getJobParameters() {
        JobParametersBuilder jobParameters = new JobParametersBuilder();
        jobParameters.addString("param", "123");
        return jobParameters.toJobParameters();
    }


    private JobParameters getNextJobParameters(JobParameters jobParameters) {
        String jobIdentifier = jobLauncherTestUtils.getJob().getName();
        List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobIdentifier, 0, 1);
        JobParametersIncrementer incrementer = jobLauncherTestUtils.getJob().getJobParametersIncrementer();
        if (lastInstances.isEmpty()) {
            return incrementer.getNext(jobParameters);
        } else {
            List<JobExecution> lastExecutions = jobExplorer.getJobExecutions(lastInstances.get(0));
            return incrementer.getNext(lastExecutions.get(0).getJobParameters());
        }
    }
}

例外是

No unique bean of type [org.springframework.batch.core.Job;] is defined: expected single matching bean but found 2: [JobA, JobB]`

7 个答案:

答案 0 :(得分:5)

也许迟到了,

但我找到了自己的工作解决方案:手动配置JobLauncherTestUtils

@Inject
@Qualifier(value = "Job1")
private Job job;

@Inject
private JobLauncher jobLauncher;

@Inject
private JobRepository jobRepository;

private JobLauncherTestUtils jobLauncherTestUtils;

private void initailizeJobLauncherTestUtils() {
    this.jobLauncherTestUtils = new JobLauncherTestUtils();
    this.jobLauncherTestUtils.setJobLauncher(jobLauncher);
    this.jobLauncherTestUtils.setJobRepository(jobRepository);
    this.jobLauncherTestUtils.setJob(job);
}

@Before
public void setUp() throws Exception {
    this.initailizeJobLauncherTestUtils();
}

使用它可以控制应该应用JobLauncherTestUtils的Job。 (默认情况下,它需要在上下文中单个作业配置)

答案 1 :(得分:2)

您在bean配置文件中声明了两个类似的bean。 要解决上述问题,您需要@Qualifier("JobA")@Qualifier("JobB")告诉Spring哪个bean应自动连接到哪个作业。

答案 2 :(得分:2)

因为在source ~/.bash_profile的设置器上有一个.zshrc批注,所以我必须在创建bean之后使用MergedBeanDefinitionPostProcessor来设置属性:

@Autowired

答案 3 :(得分:0)

我通过分别为每个作业创建JobLauncherTestUtils解决了这一问题(常规):

@TestConfiguration class BatchJobTestConfiguration {

@Autowired
@Qualifier('job1')
private Job job1

@Autowired
@Qualifier('job2')
private Job job2

@Autowired
JobRepository jobRepository;

@Bean
JobLauncher jobLauncher() throws Exception {
    SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
    jobLauncher.setJobRepository(jobRepository);
    jobLauncher.setTaskExecutor(new SyncTaskExecutor());
    jobLauncher.afterPropertiesSet();
    return jobLauncher;
}

@Bean(name = 'jobLauncherTestUtilsJob1')
JobLauncherTestUtils jobLauncherTestUtilsSyncEndUserJob() {
    new JobLauncherNoAutowireTestUtil(
            job: job1,
            jobLauncher: jobLauncher()
    )
}

@Bean(name = 'jobLauncherTestUtilsJob2')
JobLauncherTestUtils jobLauncherTestUtilsenewCaseJob() {
    new JobLauncherNoAutowireTestUtil(
            job: job2,
            jobLauncher: jobLauncher()
    )
}

然后将其添加到您的测试中:

@ContextConfiguration(classes = [BatchJobTestConfiguration])
...
@Autowired
@Qualifier('jobLauncherTestUtilsJob1')
private JobLauncherTestUtils jobLauncherTestUtils
...
when:
def jobExecution = jobLauncherTestUtils.launchJob()

答案 4 :(得分:0)

无法回答原始问题,但是使用下面的代码,我们避免了在相同类中的测试用例顺序运行期间重复使用JobLauncherTestUtils。

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)

这表示Junit在每次运行后都要清理并重建上下文。

答案 5 :(得分:0)

我们面临同样的问题,因为我们在项目中也使用了spring-cloud-configuration,需要@SpringBootTest注解,然后加载整个Spring Boot上下文,所以在上下文中加载了多个作业。

我们得到的解决方案接近于 Ilya Dyoshin 提供的解决方案,使用构造函数注入和 Junit 5:

@ExtendWith(SpringExtension.class)
@SpringBootTest
class MyJobConfigTest {

    private final JobLauncherTestUtils jobLauncherTestUtils;

    @Autowired
    public MyJobConfigTest(Job jobNumber1, JobLauncher jobLauncher, JobRepository jobRepository) {
        this.jobLauncherTestUtils = new JobLauncherTestUtils();
        this.jobLauncherTestUtils.setJobLauncher(jobLauncher);
        this.jobLauncherTestUtils.setJobRepository(jobRepository);
        this.jobLauncherTestUtils.setJob(jobNumber1);
    }

答案 6 :(得分:0)

使用 Spring Boot 时,我建议使用 @EnableBatchProcessing(modular = true)

将两个作业分离到单独的上下文中

然后可以通过仅提供带有 @SpringBootTest(classes = { JobAConfiguration.class, ... })

的特定配置来单独测试作业

有一个很棒且全面的示例,其中包括针对 https://github.com/desprez/springbatch-modular 的不同作业的单独测试类(不是我的,向作者致敬)。