title: Spring Batch: Why is the unit test running the step twice?
body: <p>I'm learning to unit test Spring Batch, but am struggling to debug a case where the Unit Test is executing the same Spring Batch job twice.</p>
  
  <p>As this is my first unit test in Spring Batch, I've tried to find some working examples of other Spring Batch unit tests for comparison, but haven't found anything beyond the manual so far!</p>
  
  <p>The Spring Batch unit test project contains exactly the same code as the <a href="https://spring.io/guides/gs/batch-processing" rel="nofollow noreferrer">Creating a Batch Service</a> tutorial, with the following exceptions:</p>
  
  <p><strong>build.gradle</strong></p>
  
  <pre><code>buildscript {
      repositories {
          mavenCentral()
      }
      dependencies {
          classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE")
      }
  }
  
  ...
  
  dependencies {
      compile("org.springframework.boot:spring-boot-starter-batch");
      compile("org.hsqldb:hsqldb");
      testCompile("junit:junit")
      testCompile("org.springframework.boot:spring-boot-starter-test");
      testCompile("org.springframework.batch:spring-batch-test");
  }
  </code></pre>
  
  <p>And the Unit Test code:</p>
  
  <p><strong>ApplicationTest</strong></p>
  
  <pre><code>package hello;
  
  import org.junit.Test;
  import org.junit.runner.RunWith;
  
  import org.springframework.batch.core.JobExecution;
  import org.springframework.batch.test.JobLauncherTestUtils;
  import org.springframework.batch.test.context.SpringBatchTest;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.context.SpringBootTest;
  import org.springframework.test.context.junit4.SpringRunner;
  
  import static org.junit.Assert.assertEquals;
  
  @SpringBatchTest
  @SpringBootTest
  @RunWith(SpringRunner.class)
  public class ApplicationTest {
  
      @Autowired
      private JobLauncherTestUtils jobLauncherTestUtils;
  
      @Test
      public void testPersonJob() throws Exception {
          JobExecution jobExecution = jobLauncherTestUtils.launchJob();
          assertEquals("COMPLETED", jobExecution.getExitStatus().getExitCode());
      }
  
  }
  </code></pre>
  
  <p>The test log shows that the Job completes as expected on the first execution...</p>
  
  <pre><code>2019-05-05 20:30:33.808  INFO 28448 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{run.id=1}]
  2019-05-05 20:30:33.886  INFO 28448 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
  2019-05-05 20:30:34.011  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Jill, lastName = Doe) into (firstName: JILL, lastName = DOE)
  2019-05-05 20:30:34.034  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Joe, lastName = Doe) into (firstName: JOE, lastName = DOE)
  2019-05-05 20:30:34.034  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Justin, lastName = Doe) into (firstName: JUSTIN, lastName = DOE)
  2019-05-05 20:30:34.034  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Jane, lastName = Doe) into (firstName: JANE, lastName = DOE)
  2019-05-05 20:30:34.034  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: John, lastName = Doe) into (firstName: JOHN, lastName = DOE)
  2019-05-05 20:30:34.049  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : !!! JOB FINISHED! Time to verify the results
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JILL, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JUSTIN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JANE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOHN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.065  INFO 28448 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED]
  </code></pre>
  
  <p>But then, <em>the same Job is executed again</em> unexpectedly for some reason:</p>
  
  <pre><code>2019-05-05 20:30:34.596  INFO 28448 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{random=785577}]
  2019-05-05 20:30:34.628  INFO 28448 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
  2019-05-05 20:30:34.659  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Jill, lastName = Doe) into (firstName: JILL, lastName = DOE)
  2019-05-05 20:30:34.659  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Joe, lastName = Doe) into (firstName: JOE, lastName = DOE)
  2019-05-05 20:30:34.659  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Justin, lastName = Doe) into (firstName: JUSTIN, lastName = DOE)
  2019-05-05 20:30:34.659  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: Jane, lastName = Doe) into (firstName: JANE, lastName = DOE)
  2019-05-05 20:30:34.674  INFO 28448 --- [           main] com.example.demo.PersonItemProcessor     : Converting (firstName: John, lastName = Doe) into (firstName: JOHN, lastName = DOE)
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : !!! JOB FINISHED! Time to verify the results
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JILL, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JUSTIN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JANE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.690  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOHN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JILL, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JUSTIN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JANE, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] c.e.d.JobCompletionNotificationListener  : Found &lt;firstName: JOHN, lastName = DOE&gt; in the database
  2019-05-05 20:30:34.753  INFO 28448 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{random=785577}] and the following status: [COMPLETED]
  </code></pre>
  
  <p>The duplicate execution only happens when running ApplicationTest; executing the Spring Boot Application does not reproduce the problem.</p>