Spring Batch - How to prevent database commits with jobLauncherTestUtils

大兔子大兔子 提交于 2021-02-07 12:55:50

问题


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;
}

回答1:


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 🤦‍♂️




回答2:


@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) may be what you are looking for, and is what I have used in the past when testing programs which alter database records. Based on the Spring Docs, @DirtiesContext is a

Test annotation which indicates that the ApplicationContext associated with a test is dirty and should therefore be closed and removed from the context cache. Use this annotation if a test has modified the context — for example, by modifying the state of a singleton bean, modifying the state of an embedded database, etc. Subsequent tests that request the same context will be supplied a new context.

Otherwise, building off of @Dan's answer, TestTransaction may allow for more explicit control of your test transactions within methods annotated with @Test, @Before, and @After. See here for more info.




回答3:


I suppose you have transactionManager, if so, add

@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)

at the top of your test class.




回答4:


Normally the strategy I use for integration tests is have a profile (as you have) with Embedded DB creation for the integration tests, with a specific application-test.properties so then the impact of them are more controlled when you are concerned about data modification and these kind of stuffs.

Regarding your case, it looks that you are in the right path adding the @Transactional for tests purposes, as we can see on this topic. Then I would invest my time investigating further about the exception you get when this error happens.

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

Also this exception looks something quite known, so I would recommend to take a look on this other topic to figure out what was tried. They had pretty much the same issue and wrote an article about how to avoid this error happening (also on this thread).

Another possibility commented is upgrade spring code version, because in some cases this issues started happening right after the upgrade.

Now, talking more about the components used, you look using spring-batch, which has its particular suite to test the batch slices and etc, so I would recommend you to take a look on how to use/test spring-batch and the spring-batch test documentation itself. Maybe using the components provided by spring-boot for batch testing there are pre-made decisions and strategies that mitigate your issue.



来源:https://stackoverflow.com/questions/39620421/spring-batch-how-to-prevent-database-commits-with-joblaunchertestutils

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!