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?
13 Answers
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
9MockitoAnnotations.initMocks(java.lang.Object testClass)
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); } } 1In 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; }