Spring boot mockito mock method according to input parameters
Solution 1:
When testing with mocks you should make clear wich class is under test and which other classes are just dependencies that should be mocked. In your case you want to test ServiceFacade
on method getMyObjectsLogByExternalCode()
.
So please keep the whole ServiceFacade object as autowired Spring bean, don't use spys or try to mock parts of it.
Please also note, that you cannot mock methods of autowired services, nor you can trick it with a spy. A spy is actually a facade that can only redirect the initial method call. Internal method calls always refer to the real object.
But as you already did, it makes sense to mock the objectRepository, as it should be ouside of your unit test scope. In your code I can see two methods of this object called:
objectRepository.findobjectCodesByExternalCode(externalCode); // called once to get the list
objectRepository.findByObjectCode(objectCode); // called twice, which each element of the list
You should both mock them with standard Mockito style:
List<String> mockObCodes = Arrays.asList("obcode1", "obcode2");
when(objectRepository.findObjectCodesByexternalCode(any())).thenReturn(mockObCodes );
List<OperationLogDTO> mockLogsOb1 = Arrays.asList( new Log(), new Log() ); //Size 2 for ob1
when(objectRepository.findByObjectCode("obcode1")).thenReturn( mockLogsOb1 );
List<OperationLogDTO> mockLogsOb2 = Collections.singletonList( new Log() ); //Size 1 for ob1
when(objectRepository.findByObjectCode("obcode2")).thenReturn( mockLogsOb2 );
I hope this will make your test run, please let me know,
Solution 2:
Firstly - try to mock only collaborators, not your object under test.
Having said that - a Spy can be used to mock parts of object under test.
I don't really see the need to use @SpringBootTest
for your service, so here goes plain Mockito version:
@ExtendWith(MockitoExtension.class)
class ObjectServiceFacadeImplTest {
@Mock
ObjectRepository repository;
@Spy
@InjectMocks
private ServiceFacadeImpl serviceFacade;
@Test
void testGetMyObjectsLogByExternalCode() {
// Given
List<String> mockObCodes = List.of("obcode1", "obcode2");
String externalCode = "TESTCODE";
when(repository.findObjectCodesByExternalCode(externalCode)).thenReturn(mockObCodes);
List<Log> mockLogsOb1 = List.of(new Log(), new Log()); //Size 2 for ob1
when(serviceFacade.getObjectLog("obcode1")).thenReturn(mockLogsOb1);
List<Log> mockLogsOb2 = List.of(new Log()); //Size 1 for ob1
when(serviceFacade.getObjectLog("obcode2")).thenReturn(mockLogsOb2);
// When
MyObjectWrapper objectWrapper = serviceFacade.getMyObjectsLogByExternalCode(externalCode);
// Then
assertEquals(objectWrapper.getExternalCode(), externalCode);
assertEquals(objectWrapper.getObjects().size(), 2);
assertEquals(objectWrapper.getObjects().get(0).getLogs().size(), 2); //Fails because it gets the second mock return value
assertEquals(objectWrapper.getObjects().get(0).getCode(), "obcode1"); //Fails because it gets the second mock return value
assertEquals(objectWrapper.getObjects().get(1).getLogs().size(), 1);
assertEquals(objectWrapper.getObjects().get(1).getCode(), "obcode2");
}
}