Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing spring batch jobs

What would be the approach to test the below scenarios in Spring Batch jobs:

1) An independent tasklet running in a step in a spring batch job.

2) A job consisting of several steps with some steps having itemreader, itemprocessor, itemwriters while some steps having tasklets.

3) An itemreader where the input query to item reader is a very complex sql query having joins from many tables - This scenario will not allow emptying all tables used and populating them with dummy data for testing. In other words, there could be real world scenarios where in it would not be possible to empty the tables for testing. What should be the approach in that case ?

If I get a little help on this forum about the approach to be taken, I want to prepare an example suite containing examples on testing spring batch jobs with different job scenarios.

like image 874
Vicky Avatar asked Oct 30 '12 09:10

Vicky


People also ask

What is Spring Batch test?

4.1. Spring Batch Test provides a useful file comparison method for verifying outputs using the AssertFile class.

How do I check my spring batch job status?

You can get the status of the last job (so, the one running if there is one running) with http://localhost:8080/sprin-batch-admin-sample/batch/jobs/job1.json (replacing with job1 your actual job name and server). The parameter lastJobExecutionStatus should be STARTING , STARTED or STOPPING if it's still running.

How do I run a specific job in spring batch?

Spring Batch auto configuration is enabled by adding @EnableBatchProcessing (from Spring Batch) somewhere in your context. By default it executes all Jobs in the application context on startup (see JobLauncherCommandLineRunner for details). You can narrow down to a specific job or jobs by specifying spring. batch.


1 Answers

It's very hard to 'unit' test a spring batch job, purely because there is so much interaction with external resources, such as databases or files etc. The approach I have has two levels:

The individual methods in the tasklets are unit tested as normal, I just call the methods directly from a JUnit test, with the usual mocks or stubs.

Secondly, I run the batch from a JUnit test, by calling the main method directly, with all of the necessary infrastructure in place. For my batch jobs, I need a database and some input files. My JUnit test copies all of the necessary files for that test into a temp directory (I use maven so usually target/it), along with a database (I have copies of my MySQL database saved in HSQLDB format). I then call Main.main() directly with the correct parameters, let the batch run and then check the results, check to see if the correct files have been generated, the database has been changed correctly etc.

This has a couple of advantages as a way of working.

  1. I can run these tests from Eclipse, so shortening the debugging cycle, because I don't need to build the full package each time to test it.
  2. They are easy to incoporate into the build, I just include them in the failsafe plugin in maven.

With a couple of warnings:

You'll need to run the main method within a SecurityManager. If your main calls System.exit(), you don't want the JVM to stop. For an example of a SecurityManager, see org.junit.tests.running.core.MainRunner. This is called like:

Integer exitValue = new MainRunner().runWithCheckForSystemExit(new Runnable() {
    public void run() {
    Main.main(new String[] {});
  }
});

Using the above, you can assert that a batch calls System.exit() with the correct values on failure, allowing testing of failure conditions as well.

Secondly, you can do a lot of setup from a JUnit test, but you can't do it all, so if for instance, you require an FTP server, I usually start it from maven rather than the JUnit, before the failsafe plugin runs. This can be a little bit fiddly sometimes.

like image 120
Matthew Farwell Avatar answered Sep 26 '22 16:09

Matthew Farwell