I have try so many time by unsing @RunWith(SpringJUnit4ClassRunner.class)
I have tried to create a test case foe a class with getter and Constructor injection. When i user @MockBean
for setter injection, @Mock
for Constructor injection and also use @RunWith(SpringJUnit4ClassRunner.class)
and MockitoAnnotations.initMocks(this);
bean injection.
If i comment MockitoAnnotations.initMocks(this);
constructor injection not working.
Now all beans are injected perfectly but @Mock
beans(Contructor injected ) beans mocked mthods not working properly when its called.
@Component
Class A{
}
@Component
Class B {
}
@Component
Class c{
}
@Component
Class D{
@Atowired
A a;
B b;
C c;
@Autowired
public D(B b,C c){
b=b;
c=c;
}
}
My Test Class is
@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass{
@MockBean
A mockA
@Mock
B mockB
@Mock
C mockC
@InjectMocks
D mockD
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);//Without this Constructor injection not working
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");
}
@Test
public void testMethod(){
mock.getAllValues();// It will call all injested bean method we are mocked in @before
}
}
The injections are working properly ,issue is belongs to mocked methods of beans which i use @Mock
is not working properly means mockB.getValue()
and mockC.getValue()
retun null
but mockA.getValue()
return correctly when i test run.
Solution :
@RunWith(SpringJUnit4ClassRunner.class)
Class TestClass {
@MockBean
A mockA
@MockBean
B mockB
@MockBean
C mockC
@Autowired
D mockD
@Before
public void setUp() {
mockD = new D(mockA,mockB);
MockitoAnnotations.initMocks(this);
when(mockA.getValue()).then("StringValA");
when(mockB.getValue()).then("StringValB");
when(mockC.getValue()).then("StringValC");
}
@Test
public void testMethod(){
mock.getAllValues(); // It will call all injested bean method we are mocked in @before
}
}
Normal bean initialize methods like SpringJUnit4ClassRunner
or MockitoAnnotations.initMocks(this);
handling only one type injection at a time. Either constructor or Auto wired injection.
@RunWith(SpringJUnit4ClassRunner.class)
means public class SpringJUnit4ClassRunner
extends BlockJUnit4ClassRunner
. SpringJUnit4ClassRunner
is a custom extension of JUnit's. It will initialize mock the @MockedBean
and @Bean
annottated beans at the initial time of test run. Also, running the bean injection also.
MockitoAnnotations.initMocks(this)
method has to called to initialize annotated fields. In above example, initMocks() is called in @Before (JUnit4) method of test's base class. For JUnit3 initMocks()
can go to setup() method of a base class.
So that in above question you have used the SpringJUnit4ClassRunner
and MockitoAnnotations.initMocks(this)
it will create two mock bean references for which ever you use the @Mock
. Also in above code flow.
At the beginning the SpringJUnit4ClassRunner
run it will create bean reference for @Mock
and @MockBean
annotated attributes.after that it will create injected bean at tjis time only happens the constructor injection
Run @Before
and Run MockitoAnnotations.initMocks(this);
it will create another mock references for @Mock annotated attributes and replaced direct reference only. and Auto wired injection run at this time.
After running the MockitoAnnotations.initMocks(this);
you will see the all beans are initialized and injected well. But beans which are injected through the constructor those beans are not correct reference these are referring old bean reference which are created by SpringJUnit4ClassRunner.
If you want to achieve the constructor and Auto wired injection for a single bean you must to use manual bean injected for the constructor injection. You can refer here.