Spring Batch - 如何使用jobLauncherTestUtils阻止数据库提交

时间:2016-09-21 15:13:57

标签: spring spring-batch spring-data-jpa spring-test

我有写入数据库的Spring Batch作业(它有一个JpaItemWriter的步骤)。我有一个集成测试,如下所示:

@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());
    }
}

在测试中运行作业时,它会提交到数据库。如何防止提交到数据库?通常,我可以在每次测试后添加@Transactional来回滚事务。但是,当我在测试类中添加注释时,我会收到:

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

更新

我尝试将@Rollback添加到测试类中。但是,JpaItemWriter仍然提交。

这是应用程序代码中事务管理器的配置:

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

4 个答案:

答案 0 :(得分:1)

为克服这个问题,我的小组仅编写了一个@After钩子以清除已写入的数据。这不是很漂亮,也不是所不希望的,但是它似乎正在使我们解决问题。

请记住,这仍然会将您的工作执行情况写入batch_job_executionbatch_job_execution_context等。

还要认识到,您可能需要确保将spring.batch.job.enabled中的false设置为test/resources/application.[properties|yml]

好玩的时光?‍♂️

答案 1 :(得分:1)

@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)可能就是您要寻找的东西,也是我过去在测试更改数据库记录的程序时使用的东西。根据{{​​3}},@DirtiesContext

Test批注,它指示与测试关联的ApplicationContext脏,因此应将其关闭并从上下文缓存中删除。 如果测试修改了上下文,请使用此注释,例如,通过修改单例bean的状态,修改嵌入式数据库的状态等。随后,请求相同上下文的测试将被提供新的上下文。

否则,以@Dan的答案为基础,TestTransaction可以在用@Test@Before@After注释的方法中更明确地控制测试事务。有关更多信息,请参见Spring Docs

答案 2 :(得分:0)

我想你有transactionManager,如果有的话,添加

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

位于测试类的顶部。

答案 3 :(得分:0)

通常,我用于集成测试的策略是profile(如您所愿)为集成测试创建Embedded DB,并带有特定的application-test.properties,因此它们的影响当您担心数据修改和此类操作时,可以更好地控制它们。

关于您的情况,看起来您在正确的位置添加@Transactional进行测试,正如我们在this topic上看到的那样。然后,我将花时间进一步调查发生此错误时遇到的异常。

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

这个异常看起来也很出名,因此我建议您看看this other topic来找出尝试过的方法。他们有几乎相同的问题,并写了一篇文章,介绍如何避免发生此错误(也在该线程上)。

评论的另一种可能性是upgrade spring code version,因为在某些情况下,此问题在升级后立即开始发生。

现在,更多地讨论所使用的组件,您将使用spring-batch,它具有特定的套件来测试批处理切片等,因此我建议您看一下how to use/test spring-batchspring-batch test documentation本身。也许使用spring-boot提供的组件进行批处理测试,有一些预先制定的决策和策略可以缓解您的问题。