'No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2:

I have 2 jobs running in single spring batch application based on input parameters and it is working successfully. But when i run my test case, i'm getting the below error. I'm using gradle to build my application.

No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2: pureRedDataProcessingJob,pcsMasterProcessingJob

Test class:

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**

 * 
 * @author 
 *
 */
@ContextConfiguration(classes = {UidBatchApplication.class, JobLauncherTestUtils.class}, 
initializers = ConfigFileApplicationContextInitializer.class)
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations = {"classpath:application-test.properties"})
@Configuration
@ActiveProfiles("test")
@Profile("test")
@TestConfiguration
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)

@EnableAutoConfiguration

public class UidBatchApplicationTest {


    @Autowired
    public JobLauncherTestUtils jobLauncherTestUtils;


    @Test
    public void launchJob() throws Exception {
        JobParameters params = new JobParametersBuilder().addString("jobName", "pcsMasterProcessingJob").toJobParameters();
        jobLauncherTestUtils.launchJob(params);
    }

}

Main class configuration:

/*

 */



import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.sql.DataSource;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;




@Configuration
@ConfigurationProperties
@EnableBatchProcessing

public class UidApplicationConfiguration{

    @Autowired
    private DataSource mariaDb;

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public JobExecutionListener listener() {
        return new JobCompletionNotificationListener();
    }

    @Bean
    @Qualifier("pureRedDataProcessingJob")
    public Job pureRedDataProcessingJob() {
        return jobBuilderFactory.get(UidConstants.PURE_RED_JOB)
                .incrementer(new RunIdIncrementer()).listener(listener())
                .flow(pureRedStep()).end().build();
    }

    @Bean
    public Step pureRedStep() {
        return stepBuilderFactory.get("pureRedStep").<PureRedBean, PureRedBean> chunk(1)
                .reader(multiResourcePureRedReader()).processor(pureRedProcessor()).writer(pureRedWriter()).faultTolerant()
                .build();
    }

    @Bean
    public MultiResourceItemReader<PureRedBean> multiResourcePureRedReader()
    {
        MultiResourceItemReader<PureRedBean> resourceItemReader = new MultiResourceItemReader<>();
        resourceItemReader.setResources(getPureredFilePath());
        resourceItemReader.setDelegate(pureRedReader());
        return resourceItemReader;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FlatFileItemReader<PureRedBean> pureRedReader()
    {
        String[] namesArray = {"circularType","rotoKey","xyCoordinate","xyCoordinate","xyCoordinate","adPrintVerNum",
                "adStartDttm","pageNum","itemWic","upc","headLineCopy","bodyCopy","xyCoordinate","pluCode",
                "vendorName","xyCoordinate","xyCoordinate","xyCoordinate","imageFileName","xyCoordinate",
                "offerPrice","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "quantity","getFree","rewardSpend","rewardPoints","rewardQuantity","percentOff","offerLimit",
                "templateName","adPriceVerbiage","rewardVerbiage","fsiVerbiage","mirVerbiage",
                "ivcVerbiage","retailVerbiage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "sevenPartKey","fillerThree","largeImage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
                "summary","additionalDealInfo","disclaimer","smallImage"};
        PureredBeanWrapperFieldSetMapper beanWrapper = new PureredBeanWrapperFieldSetMapper();
        beanWrapper.setTargetType(PureRedBean.class);
        DefaultLineMapper linemapper = new DefaultLineMapper();
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
        tokenizer.setNames(namesArray);
        linemapper.setLineTokenizer(tokenizer );
        beanWrapper.setDistanceLimit(0);
        linemapper.setFieldSetMapper(beanWrapper);

        //Create reader instance
        FlatFileItemReader<PureRedBean> reader = new FlatFileItemReader<>();         
        reader.setLineMapper(linemapper);
        return reader;
    }

    @Bean
    public ItemWriter<PureRedBean> pureRedWriter() {        
        JdbcBatchItemWriter<PureRedBean> writer = new JdbcBatchItemWriter<>();
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<PureRedBean>());
        writer.setSql(pureredInsertQuery);      
        writer.setDataSource(mariaDb);
        return writer;
    }

    @Bean
    public PureRedProcessor pureRedProcessor() {
        return new PureRedProcessor();
    }

    @Bean
    @Qualifier("pcsMasterProcessingJob")
    public Job pcsMasterProcessingJob() {
        return jobBuilderFactory.get(UidConstants.PCS_MASTER_JOB)
                .incrementer(new RunIdIncrementer()).listener(listener())
                .flow(masterStep()).end().build();
    }

    @Bean
    public Step masterStep() {
        return stepBuilderFactory.get("masterStep").<UniqueIdMasterBean, UniqueIdMasterBean> chunk(1)
                .reader(multiResourceItemReader()).processor(masterProcessor()).writer(writer()).faultTolerant()
                .build();
    }

    @Bean
    public MultiResourceItemReader<UniqueIdMasterBean> multiResourceItemReader()
    {
        MultiResourceItemReader<UniqueIdMasterBean> resourceItemReader = new MultiResourceItemReader<>();
        resourceItemReader.setResources(getFilePath());
        resourceItemReader.setDelegate(reader());
        return resourceItemReader;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FlatFileItemReader<UniqueIdMasterBean> reader()
    {
        String[] namesArray = {"uniqueId","spotSeqNum","adTypeCd","adMarketCd","adStartDttm","adExpiryDttm",
                "adEventType","adSeqNum","adVerCd","adVerSeqNum","adPrintVerNum","adLoyaltyOfferCd","adItemCouponNum",
                "adItemLayoutPosNum","adItemPageNum","adItemRetailMultiple","adItemRetailPrice","adItemSingleUnitPrice",
                "adItemAltPriceMult","adItemAltPrice","adItemAmtOff","adItemPercentOff","adPageTypeCd","minOrderValue",
                "rewardType","offerValue","loyaltyPoints","targetedFlag","","categoryLevelTwo","adFillerOne",
                "adFillerTwo","adFillerThree","statusFlagOne","statusFlagTwo"};
        BeanWrapperFieldSetMapperCustom beanWrapper = new BeanWrapperFieldSetMapperCustom();
        beanWrapper.setTargetType(UniqueIdMasterBean.class);
        DefaultLineMapper linemapper = new DefaultLineMapper();
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
        tokenizer.setNames(namesArray);
        linemapper.setLineTokenizer(tokenizer );
        linemapper.setFieldSetMapper(beanWrapper);

        //Create reader instance
        FlatFileItemReader<UniqueIdMasterBean> reader = new FlatFileItemReader<>();      
        reader.setLineMapper(linemapper);
        return reader;
    }

    @Bean
    public ItemWriter<UniqueIdMasterBean> writer() {        
        JdbcBatchItemWriter<UniqueIdMasterBean> writer = new JdbcBatchItemWriter<>();
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<UniqueIdMasterBean>());
        writer.setSql(insertQuery);     
        writer.setDataSource(mariaDb);
        return writer;
    }

    @Bean
    public MasterProcessor masterProcessor() {
        return new MasterProcessor();
    }

    @Value("${master.filePath}")
    private Resource[] filePath;
    @Value("${master.insertQuery}")
    private String insertQuery;
    @Value("${purered.filePath}")
    private Resource[] pureredFilePath;
    @Value("${purered.insertQuery}")
    private String pureredInsertQuery;
    @Value("${categoryList}")
    private String categoryList;
    private Map<String,String> categoryMap;

    public Resource[] getPureredFilePath() {
        return pureredFilePath;
    }

    public Resource[] getFilePath() {
        return filePath;
    }

    public void setCategoryList(String categoryList) {
        this.categoryList = categoryList;
    }

    /**
     * @return the clientTagsMap
     */
    public Map<String, String> getCategoryMap() {
        if(null == categoryMap){
            categoryMap = new HashMap<>();
            int count = 0;
            String current = "";
            String value = null;
            String key = null ;
            StringTokenizer tok = new StringTokenizer(categoryList, ",=");
            while (tok.hasMoreTokens()) {
                current = tok.nextToken();
                // the first token in the pair is the key
                if (count%(PCSConstants.KEY_LENGTH)==1){
                    value =  current;
                    categoryMap.put(key, value);
                }else{
                    // the second is the value
                    key = current;
                }
                count++;
            }
        }
        return categoryMap;
    }
}

Could someone help me please.



Solution 1:[1]

You may need to manually configure JobLauncherTestUtils. This looks like similar to the thread here Spring Batch JUnit test for multiple jobs

Look into the code of JobLauncherTestUtils, which is causing the issue.

@Autowired
    public void setJob(Job job) {
        this.job = job;
    }

Solution 2:[2]

I had the same problem, and solved it by adding the following:

@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, 
  DirtiesContextTestExecutionListener.class})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)

see https://www.baeldung.com/spring-batch-testing-job

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Legna