Multiple levels of @Mock and @InjectMocks

JavaMockito

Java Problem Overview


So I understand that in Mockito @InjectMocks will inject anything that it can with the annotation of @Mock, but how to handle this scenario?

@Mock
private MockObject1 mockObject1;

@Mock
private MockObject2 mockObject2;

@InjectMocks
private SystemUnderTest systemUnderTest = new SystemUnderTest();

Imagine that MockObject2 has an attribute that is of type MockObject1, and SystemUnderTest has an attribute of type MockObject2. I would like to have mockObject1 injected into mockObject2, and mockObject2 injected into systemUnderTest.

Is this possible with annotations?

Java Solutions


Solution 1 - Java

Since I didn't get any response here I asked on the Mockito forums. Here is a link to the discussion: https://groups.google.com/d/topic/mockito/hWwcI5UHFi0/discussion

To summarize the answers, technically this would kind of defeat the purpose of mocking. You should really only mock the objects needed by the SystemUnderTest class. Mocking things within objects that are themselves mocks is kind of pointless.

If you really wanted to do it, @spy can help

Solution 2 - Java

It is possible by combining @Spy with @InjectMocks. For your example, it would be:

@Spy
private MockObject1 mockObject1 = new MockObject1 ();

@Spy @InjectMocks //if MockObject2 has a MockObject1, then it will be injected here.
private MockObject2 mockObject2 = new MockObject2 ();

@InjectMocks
private SystemUnderTest systemUnderTest;

Solution 3 - Java

Other solution I found is using java sintax instead annotation to make the @Spy object injected.

@Spy
private MockObject1 mockObject1 = new MockObject1 ();

@InjectMocks //if MockObject2 has a MockObject1, then it will be injected here.
private MockObject2 mockObject2 = spy(MockObject2.class);

@InjectMocks
private SystemUnderTest systemUnderTest;

Solution 4 - Java

This works for me:

private MockObject1 mockObject1 = mock(MockObject1.class);

@Spy
private RealObject2 realObject = new RealObject2(mockObject1);

@InjectMocks
private SystemUnderTest systemUnderTest = new SystemUnderTest();

Solution 5 - Java

Here is my solution:

@ExtendWith(SpringExtension.class)
class DocumentServiceTestMock {

//2nd Level Dependency
CustomerFacade customerFacade = Mockito.mock(CustomerFacade.class);

//Direct Dependency
@Spy
PostCreateHelper postCreateHelper = new PostCreateHelper(customerFacade);

//SUT
@InjectMocks
DocumentService documentService;

@BeforeEach
void setUp() {
        given(customerFacade.getString()).willReturn("customerFacade_MOCKED");
}

@Test
void test() {
     String documentAsResource = documentService.getDocumentAsResource(ExportType.WORD);
}
//----------
@Service
public class DocumentService {
   final PostCreateHelper postCreateHelper;

@Component
public class PostCreateHelper {
   final CustomerFacade customerFacade;

@Service
public class CustomerFacade {

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCollin PetersView Question on Stackoverflow
Solution 1 - JavaCollin PetersView Answer on Stackoverflow
Solution 2 - JavaMattCView Answer on Stackoverflow
Solution 3 - Javaz1lV3rView Answer on Stackoverflow
Solution 4 - JavapenghuoView Answer on Stackoverflow
Solution 5 - JavarazvangView Answer on Stackoverflow