Spring Batch unit test example

In this tutorial, we will show you how to unit test Spring batch jobs with jUnit and TestNG frameworks. To unit test batch job, declares spring-batch-test.jar, @autowired the JobLauncherTestUtils, launch the job or step, and assert the execution status.

1. Unit Test Dependencies

To unit test Spring batch, declares following dependencies :

pom.xml

	<!-- Spring Batch dependencies -->
	<dependency>
		<groupId>org.springframework.batch</groupId>
		<artifactId>spring-batch-core</artifactId>
		<version>2.2.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.batch</groupId>
		<artifactId>spring-batch-infrastructure</artifactId>
		<version>2.2.0.RELEASE</version>
	</dependency>
	
	<!-- Spring Batch unit test -->	
	<dependency>
		<groupId>org.springframework.batch</groupId>
		<artifactId>spring-batch-test</artifactId>
		<version>2.2.0.RELEASE</version>
	</dependency>
		
	<!-- Junit -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.11</version>
		<scope>test</scope>
	</dependency>

	<!-- Testng -->
	<dependency>
		<groupId>org.testng</groupId>
		<artifactId>testng</artifactId>
		<version>6.8.5</version>
		<scope>test</scope>
	</dependency>	

2. Spring Batch Jobs

A simple job, later unit test the execution status.

spring-batch-job.xml

    <!-- ...... -->
    <batch:job id="testJob">
	<batch:step id="step1">
	    <batch:tasklet>
		<batch:chunk reader="xmlItemReader" 
			writer="oracleItemWriter"
			commit-interval="1">
		</batch:chunk>
	    </batch:tasklet>
	</batch:step>
    </batch:job>

3. jUnit Examples

Launches a the job and assert the execution status.

AppTest.java

package com.mkyong;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:spring/batch/jobs/spring-batch-job.xml",
    "classpath:spring/batch/config/context.xml",
    "classpath:spring/batch/config/test-context.xml"})
public class AppTest {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;
    
    @Test
    public void launchJob() throws Exception {

	//testing a job
        JobExecution jobExecution = jobLauncherTestUtils.launchJob();
        
	//Testing a individual step
        //JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1");
        
        assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
        
    }
}

P.S Assume context.xml is declared all the require Spring batch core components, like jobRepository and etc.

This JobLauncherTestUtils must be declares manually.

test-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 
    <!-- Spring should auto load this bean -->
    <bean class="org.springframework.batch.test.JobLauncherTestUtils"/>
    
</beans>

4. TestNG Examples

Equivalent example in TestNG framework.

AppTest2.java

package com.mkyong;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;

@ContextConfiguration(locations = {
    "classpath:spring/batch/jobs/spring-batch-job.xml",
    "classpath:spring/batch/config/context.xml",
    "classpath:spring/batch/config/test-context.xml"})
public class AppTest2 extends AbstractTestNGSpringContextTests {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    
    @Test
    public void launchJob() throws Exception {

        JobExecution jobExecution = jobLauncherTestUtils.launchJob();
        Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);
        
    }
}

Done.

Download Source Code

Download it – SpringBatch-UnitTest-Example.zip (83 KB)

References

  1. JobLauncherTestUtils JavaDoc
  2. Spring Batch Unit Testing official documentation

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
4 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
5 Comment authors
JulienSaocroShreyas KJérôme Vkim hyungsuk Recent comment authors
newest oldest most voted
Shreyas K
Guest
Shreyas K

Hi, Thanks a lot for this wonderful post. I have implemented your example and it’s working fine, except for the last Assert statement. The issue is that, call to launchJob() is asynchronous and soon after the call to launchJob(), next line gets executed i.e. (Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);) and the status of my job is STARTED so the assert fails. For running the test case, I have added the while condition checking for COMPLETED status, so that the test case would succeed. JobExecution jobExecution = jobLauncherTestUtils.launchJob(); while(jobExecution.getStatus() != BatchStatus.COMPLETED) { continue; } Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED); Just wondering, is there any better way of… Read more »

Julien
Guest
Julien

Hi,

I had the same problem. This is because my taskExecutor was Asynchrone.
So I defined for my test only, a new jobLauncher with a SyncTask Excecutor :

and a new JobLauncher
@Component
public class Test1JobLauncher {

@Inject
@Qualifier(value = “aggregate-test1-datamart”)
private Job job;

@Inject
@Qualifier(value = “jobLauncherSynchrone”)
private JobLauncher jobLauncher;

@Inject
private JobRepository jobRepository;

private JobLauncherTestUtils jobLauncherTestUtils;

private void initializeJobLauncherTestUtils() {
this.jobLauncherTestUtils = new JobLauncherTestUtils();
this.jobLauncherTestUtils.setJobLauncher(jobLauncher);
this.jobLauncherTestUtils.setJobRepository(jobRepository);
this.jobLauncherTestUtils.setJob(job);
}

@Before
public void setUp() throws Exception {
this.initializeJobLauncherTestUtils();
}

public JobLauncherTestUtils getJobLauncherTestUtils() {
return jobLauncherTestUtils;
}
}

Saocro
Guest
Saocro

Hi, how about if there is a multiple job? Can you help me how to run the another job? I tried it will your example but I ended up running only one job. Thanks

Jérôme V
Guest
Jérôme V

Hi,

Thx for this :)

kim hyungsuk
Guest
kim hyungsuk

thank.~ i want it~