问题
I am using Spring boot and Spring batch. I have defined more than one job.
I am trying to build junit to test specific task within a job.
Therefor I am using the JobLauncherTestUtils library.
When I run my test case I always get NoUniqueBeanDefinitionException.
This is my test class:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {BatchConfiguration.class})
public class ProcessFileJobTest {
@Configuration
@EnableBatchProcessing
static class TestConfig {
@Autowired
private JobBuilderFactory jobBuilder;
@Autowired
private StepBuilderFactory stepBuilder;
@Bean
public JobLauncherTestUtils jobLauncherTestUtils() {
JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJob(jobUnderTest());
return jobLauncherTestUtils;
}
@Bean
public Job jobUnderTest() {
return jobBuilder.get("job-under-test")
.start(processIdFileStep())
.build();
}
@Bean
public Step processIdFileStep() {
return stepBuilder.get("processIdFileStep")
.<PushItemDTO, PushItemDTO>chunk(1) //important to be one in this case to commit after every line read
.reader(reader(null))
.processor(processor(null, null, null, null))
.writer(writer())
// .faultTolerant()
// .skipLimit(10) //default is set to 0
// .skip(MySQLIntegrityConstraintViolationException.class)
.build();
}
@Bean
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
public ItemStreamReader<PushItemDTO> reader(@Value("#{jobExecutionContext[filePath]}") String filePath) {
...
return itemReader;
}
@Bean
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
public ItemProcessor<PushItemDTO, PushItemDTO> processor(@Value("#{jobParameters[pushMessage]}") String pushMessage,
@Value("#{jobParameters[jobId]}") String jobId,
@Value("#{jobParameters[taskId]}") String taskId,
@Value("#{jobParameters[refId]}") String refId)
{
return new PushItemProcessor(pushMessage,jobId,taskId,refId);
}
@Bean
public LineMapper<PushItemDTO> lineMapper() {
DefaultLineMapper<PushItemDTO> lineMapper = new DefaultLineMapper<PushItemDTO>();
...
return lineMapper;
}
@Bean
public ItemWriter writer() {
return new someWriter();
}
}
@Autowired
protected JobLauncher jobLauncher;
@Autowired
JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void processIdFileStepTest1() throws Exception {
JobParameters jobParameters = new JobParametersBuilder().addString("filePath", "C:\\etc\\files\\2015_02_02").toJobParameters();
JobExecution jobExecution = jobLauncherTestUtils.launchStep("processIdFileStep",jobParameters);
}
and thats the exception:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.batch.core.Job] is defined: expected single matching bean but found 3: jobUnderTest,executeToolJob,processFileJob
Any idea? Thanks.
added BatchConfiguration class:
package com.mycompany.notification_processor_service.batch.config;
import com.mycompany.notification_processor_service.common.config.CommonConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
@ComponentScan("com.mycompany.notification_processor_service.batch")
@PropertySource("classpath:application.properties")
@Configuration
@Import({CommonConfiguration.class})
@ImportResource({"classpath:applicationContext-pushExecuterService.xml"/*,"classpath:si/integration-context.xml"*/})
public class BatchConfiguration {
@Value("${database.driver}")
private String databaseDriver;
@Value("${database.url}")
private String databaseUrl;
@Value("${database.username}")
private String databaseUsername;
@Value("${database.password}")
private String databasePassword;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseDriver);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUsername);
dataSource.setPassword(databasePassword);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
and this is CommonConfiguration
@ComponentScan("com.mycompany.notification_processor_service")
@Configuration
@EnableJpaRepositories(basePackages = {"com.mycompany.notification_processor_service.common.repository.jpa"})
@EnableCouchbaseRepositories(basePackages = {"com.mycompany.notification_processor_service.common.repository.couchbase"})
@EntityScan({"com.mycompany.notification_processor_service"})
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableAsync
public class CommonConfiguration {
}
回答1:
I had the same issue and the easier way is injecting in the setter of JobLauncherTestUtils
like Mariusz explained in Jira of Spring:
@Bean public JobLauncherTestUtils getJobLauncherTestUtils() { return new JobLauncherTestUtils() { @Override @Autowired public void setJob(@Qualifier("ncsvImportJob") Job job) { super.setJob(job); } }; }
回答2:
So I see the jobUnderTest bean. Somewhere in all those imports, you're importing the two other jobs as well. I see your BatchConfiguration
class imports other stuff as well as you having component scanning turned on. Carefully trace through all your configurations. Something is picking up the definitions for those beans.
回答3:
I also ran into this issue and couldn't have JobLauncherTestUtils to work properly. It might be caused by this issue
I ended up autowiring the SimpleJobLauncher and my Job into the unit test, and simply
launcher.run(importAccountingDetailJob, params);
回答4:
An old post, but i thought of providing my solution as well.
In this case i am automatically registering a JobLauncherTestUtils
per job
@Configuration
public class TestConfig {
private static final Logger logger = LoggerFactory.getLogger(TestConfig.class);
@Autowired
private AbstractAutowireCapableBeanFactory beanFactory;
@Autowired
private List<Job> jobs;
@PostConstruct
public void registerServices() {
jobs.forEach(j->{
JobLauncherTestUtils u = create(j);
final String name = j.getName()+"TestUtils"
beanFactory.registerSingleton(name,u);
beanFactory.autowireBean(u);
logger.info("Registered JobLauncherTestUtils {}",name);
});
}
private JobLauncherTestUtils create(final Job j) {
return new MyJobLauncherTestUtils(j);
}
private static class MyJobLauncherTestUtils extends JobLauncherTestUtils {
MyJobLauncherTestUtils(Job j) {
this.setJob(j);
}
@Override // to remove @Autowire from base class
public void setJob(Job job) {
super.setJob(job);
}
}
}
来源:https://stackoverflow.com/questions/28293266/joblaunchertestutils-throws-nouniquebeandefinitionexception-while-trying-to-test