Hot questions for Using Mockito in spring batch

Top 10 Java Open Source / Mockito / spring batch

Question:

Is there a way with mockito to test my batch and tell to not invoke specific method that the process call MyService.class, inside that service i got some business logic in a specific method that i don't want him to invoke is that possible? I was sure that doing the doReturn will ignore my method (the method is public) but still get call.

   @Autowired
        private JobLauncherTestUtils jobLauncherTestUtils;


        @Autowired
        private MyRepo myRepoRepository; 



        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);
        }

        @Test
        public void testJob() throws Exception {

        doReturn(true).when(spy(MyService.class)).validationETPer(any(Object.class), anyChar());
        doReturn(true).when(spy(MyService.class)).validationMP(any(Object.class),anyChar());
        JobExecution execution = jobLauncherTestUtils.launchJob(); 


        assertEquals(execution.getStepExecutions().size(), 1); 
    for (StepExecution stepExecution : execution.getStepExecutions()) {

            assertEquals(3, stepExecution.getReadCount()); 
            assertEquals(3, stepExecution.getWriteCount()); 
        }

        assertEquals(ExitStatus.COMPLETED.getExitCode(), execution.getExitStatus().getExitCode());

        assertEquals(2, myRepoRepository.count()); 
  }  

Answer:

This line does not what you believe it does:

doReturn(true).when(spy(MyService.class)).validationETPer(any(Object.class), anyChar());

spy(MyService.class) creates a new instance of MyService and spies on it. Of course, since you never use that instance, it's completely useless. There is an instance that is spied on, but you didn't store it anywhere, you didn't put it anywhere and so nobody will ever use it.

That line does not spy on every MyService in existence, as you seem to believe, it creates one concrete instance of MyService and spies on that. Obviously, that's not what you want here - you want to spy on the instance that is actually used in your code.

What you probably wanted to do, is more something like this...

MyService mySpy = spy(MyService.class);
doReturn(true).when(mySpy).validationETPer(any(Object.class), anyChar());
jobLauncherTestUtils.setMyService( mySpy ); // or something like that
// and NOW you can test

It's hard to go deeper in the details without knowing how the MyService is used in your actual code. Personally, I would suggest starting with unit tests without spring and using spring test only for higher level tests.