I am using mockito to mock a JpaRepository class that returns a list of Object[]. The mocking is as follow:
@MockBean
private UtilisateurSuiviRepository utilisateurSuiviRepository;
So I'm using this mock object o test diffrent scenarios and return different results.
In the first test method I have this:
when(utilisateurSuiviRepository
.findUtilisateursInactifsPourPremiereRelance(10))
.thenReturn(new ArrayList<Object[]>(){{
add(new Object[]{8L, Instant.now()});
}});
In the second test method I have the same thing but with different parameter and return result:
when(utilisateurSuiviRepository
.findUtilisateursInactifsPourPremiereRelance(16))
.thenReturn(new ArrayList<Object[]>(){{
add(new Object[]{5L,null});
}});
The problem is that depending on the execution order of the methods, my second method remember also the return result of the first mock, so it returns two lists :
new Object[]{8L, Instant.now() // <-- first list of array object
new Object[]{5L,null} //<-- second list of array object
Expecting result is:
new Object[]{5L,null} //<-- what should I get in the second method
I'am aware that mockito keeps the same state for all mocks, so I did this to init the mocks before each test method:
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
But it does not change anything and I keep getting the same issue.
Note that I'm using SpringRunner to run my test class in a context of spring batch:
@RunWith(SpringRunner.class)
@MyCustomBatchUnitTest
@TestPropertySource(properties = {"spring.batch.job.names=myJob"})
The definition of MyCustomBatchUnitTest is as follow:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootTest(classes = { CommonsConfiguration.class })
@AutoConfigureMockMvc
@ActiveProfiles({CommonsConfiguration.PROFILE_BATCH, CommonsConfiguration.PROFILE_TEST, CommonsConfiguration.PROFILE_BATCHTEST})
public @interface MyCustomBatchUnitTest{
}
I tried also to init the mock manually inside each method as follow:
utilisateurSuiviRepository = mock(UtilisateurSuiviRepository.class);
when(utilisateurSuiviRepository
.findUtilisateursInactifsPourPremiereRelance(16))
.thenReturn(new ArrayList<Object[]>(){{
add(new Object[]{8L, Instant.now()});}});
But in that case the mock method that is just after is not being processed.
Bellow a github link that produce the same problem: https://github.com/MrPenguina/mockito_issue/blob/main/JobTest.java
As explained by the guys in the comments, I had to use:
Mockito.reset(utilisateurSuiviRepository);
Because MockitoAnnotations.initMocks
method is used within @Mock
of Mockito framework and not for @MockBean
of spring framework.
Also note that in the context of Spring Batch, I had a final List
that I initialize in the declaration, the list is used to hold the result of my JpaRepository
by calling the method addAll
inside the beforeStep
method, which was causing the issue in my case and kept giving me a cumulative result:
private final List<Object[]> listeUtilisateurSuiviInactif = new ArrayList<>();
I had to move the initialization of this list inside the beforeStep()
of the reader so like that the list will be initialized each time whenever a test method is called.
In conclusion, I had to correct the mistake above and to use Mockito.reset
method inside the @Before
method.
Other alternative to keep the list intitialization in the declaration instead is to use the annotation @DirtiesContext
withing the test class:
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)