How to use @InjectMocks along with @Autowired annotation in Junit

JavaSpringJunitMockingMockito

Java Problem Overview


I have a class A which is using 3 differnt classes with autowiring

public class A () {
	
	@Autowired
    private B b;
	
	@Autowired
    private C c;
	
	@Autowired
    private D d;
}

While testing them, i would like to have only 2 of the classes (B & C) as mocks and have class D to be Autowired as normal running, this code is not working for me:

@RunWith(MockitoJUnitRunner.class)
public class aTest () {
	
	@InjectMocks
	private A a;
	
	@Mock
    private B b;
	
	@Mock
    private C c;
	
	@Autowired
    private D d;
}

Is it even possible to do so?

Java Solutions


Solution 1 - Java

It should be something like

@RunWith(SpringJUnit4ClassRunner.class)
public class aTest () {

    @Mock
    private B b;

    @Mock
    private C c;

    @Autowired
    @InjectMocks
    private A a;

}

If you want D to be Autowired dont need to do anything in your Test class. Your Autowired A should have correct instance of D. Also i think you need to use SpringJUnit4ClassRunner for Autowiring to work, with contextConfiguration set correctly. Because you are not using MockitoJunitRunner you need to initialize your mocks yourself using

> MockitoAnnotations.initMocks(java.lang.Object testClass)

Solution 2 - Java

I was facing same problem and tried the answer by Sajan Chandran. It didn't work in my case because I'm using @SpringBootTest annotation to load only a subset of all my beans. The goal is not to load the beans that I'm mocking since they have lot of other dependencies and configurations.

And I found the following variant of the solution to work for me, which is usable in normal case also.

@RunWith(SpringRunner.class)
@SpringBootTest(classes={...classesRequired...})
public class aTest () {

    @Mock
    private B b;

    @Mock
    private C c;

    @Autowired
    @Spy
    private D d;

    @InjectMocks
    private A a;

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

}

Solution 3 - Java

In addition to accepted answer, if you are using spring-boot, it's easier to use @MockBean annotation (that creates a mock and add it as a bean to the context, replacing it if it exists):

@RunWith(SpringRunner.class)
public class aTest () {

    @MockBean
    private B b;

    @MockBean
    private C c;

    @Autowired
    private A a;
}

In case you are not using spring-boot, the problem with @Autowired + @InjectMocks is that Spring will load unneeded instances for beans B and C first, and then they are replaced by the mocks. This is a waste and could have transitive dependencies that you don't want/can't load. It's always recommended to load the minimum Spring context for your testing. I would recommend this:

@RunWith(SpringRunner.class)
@Import({A.class, D.class})
@ContextConfiguration(classes = aTest.class)
public class aTest () {

    @Bean
	private B b() {
    	return Mockito.mock(B.class);
	}

	@Bean
	private C c() {
		return Mockito.mock(C.class);
	}

    @Autowired
    private A a;
}

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
QuestionUSer22999299View Question on Stackoverflow
Solution 1 - JavaSajan ChandranView Answer on Stackoverflow
Solution 2 - JavaThomasView Answer on Stackoverflow
Solution 3 - JavaAníbalView Answer on Stackoverflow