Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Batch - How to prevent database commits with jobLauncherTestUtils

I have Spring Batch job that writes to the database (it has a step with a JpaItemWriter). I have an integration test such as follows:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("integrationTest")
public class LoadApplicationTests {

    @Autowired
    private Job job;

    @Autowired
    private JobRepository jobRepository;

    @Autowired
    private JobLauncher jobLauncher;

    private JobLauncherTestUtils jobLauncherTestUtils;

    @Before
    public void setUp() throws IOException, java.text.ParseException, Exception {       
        jobLauncherTestUtils = new JobLauncherTestUtils();
        jobLauncherTestUtils.setJob(job);
        jobRepository = new MapJobRepositoryFactoryBean(new ResourcelessTransactionManager()).getObject();
        jobLauncherTestUtils.setJobRepository(jobRepository);
        jobLauncherTestUtils.setJobLauncher(jobLauncher);
    }

    @Test
    public void testJob() throws Exception {
        JobParametersBuilder j = new JobParametersBuilder();
        JobParameters jobParameters = j.addDate("runDate", new Date())
                .addString("file", testFile.getAbsolutePath())
                .addString("override", "false")
                .addString("weekly", "false")
                .toJobParameters();

        JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);

        Assert.assertEquals("COMPLETED", jobExecution.getExitStatus().getExitCode());
    }
}

When running the job in the test, it commits to the database. How can I prevent committing to the database? Normally, I could add @Transactional to rollback the transaction after each test. However, when I add the annotation the test class, I receive:

java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove @Transactional annotations from client).

Update

I have tried to add @Rollback to the test class. However, the JpaItemWriter still commits.

Here's the configuration for the transaction manager in the application code:

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
}

@Bean
public Step stepLoadFile(StepBuilderFactory stepBuilderFactory, 
        PlatformTransactionManager transactionManager,
        ItemReader<MyClass> reader, ItemProcessor<MyClass, 
        MyClass> processor, 
        ItemWriter<MyClass> writer, 
        ReadFailureHandler readListenerSupport,
        WriteFailureHandler writeListenerSupport) {
    Step step = stepBuilderFactory.get("stepPersistFile")
            .transactionManager(transactionManager)
            .<MyClass, MyClass> chunk(1000)      
            .reader(reader)
            .processor(processor)
            .listener(writeListenerSupport)
            .listener(readListenerSupport)
            .writer(writer)
            .build();

    return step;
}
like image 892
James Avatar asked Sep 21 '16 15:09

James


People also ask

What is the difference between Tasklet and chunk in Spring Batch?

One approach is tasklet-based, where a Tasklet supports a simple interface with a single execute() method. The other approach, **chunk-oriented processing**, refers to reading the data sequentially and creating "chunks" that will be written out within a transaction boundary.

How do you stop a step in Spring Batch?

The second and preferred way to stop execution is to set a stop flag in the step execution object. To set this stop flag, call the method StepExecution. setTerminateOnly() , which is equivalent to sending a stop message. As soon as Spring Batch gets control of the processing, it stops the job execution.

How does Spring Batch handle exceptions?

By default , if there's an uncaught exception when processing the job, spring batch will stop the job. If the job is restarted with the same job parameters, it will pick up where it left off. The way it knows where the job status is by checking the job repository where it saves all the spring batch job status.

How does JobExecutionDecider help in Spring Batch process?

The JobExecutionDecider is an interface provided by Spring Batch that, when implemented, gives you the ability to examine a condition during job execution and return a FlowExecutionStatus value to determine the next step in the job.


1 Answers

To overcome this my group has simply written an @After hook to clear the data that was written. It is not pretty, nor desired, but it appears to be getting us through our issues.

Keep in mind, that this will still write your job executions to batch_job_execution, batch_job_execution_context, etc.

Also recognize, that you'll probably want to ensure your spring.batch.job.enabled should be set to false in your test/resources/application.[properties|yml].

Fun times 🤦‍♂️

like image 67
Dan Avatar answered Oct 07 '22 11:10

Dan