InjectMocks doesn't re-inject new mocks to final fields when constructor injection is used
See original GitHub issueHello,
My class under test uses constructor to set final field(s), which (in test) I want to create/inject by @InjectMocks and @Mock annotation before every test method. Everything works nice in first test. Second however, the @Mock is recreated, but the @InjectMocks instance is not. As a result, if I stub in second test method, it is actually different mock then class under test is using. Example (mocikto version 2.18.3 + testng, assertj):
public class ConstructorInjectionProblemTest {
interface Foo {
Integer bar();
}
static class Testee {
private final Foo foo;
public Testee(Foo foo) {
this.foo = foo;
}
public Integer fooBar() {
return foo.bar();
}
}
@InjectMocks
private Testee testee;
@Mock
private Foo foo;
@BeforeMethod
public void prepare() {
MockitoAnnotations.initMocks(this);
}
@Test
public void test1 () {
}
@Test
public void test2() {
when(foo.bar()).thenReturn(5);
assertThat(testee.fooBar()).isEqualTo(5);
//fails, because foo here (in test2()) is different then the one created in prepare()
}
}
From what I can see, mocks are re-created before every test method, but FieldInitializer.initialize() (called inside ConstructorInjection) creates the Testee instance only if it doesn’t exist yet - so not before test2(). Afterwards field setter injection tries to set newly created mocks to testee - what silently fails. So when I stub in test2(), foo is different instance then testee.foo. There is couple of workarounds, eg setting testee to null in @AfterMethod or removing the @InjectMocks and creating the Testee instance manually or removing the final modifier, etc. Is this intended or is it a bug?
Thanks,
Juraj
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
A quick note for anyone stumbling on this issue and wondering how to fix this.
You can “clarify the intention” for mockito by setting your injected object to null before running initMocks() to get a new instance for each test.
in the OP’s example it would look like :
With jUnit 5 it became possible to launch test lifecycle by class. Does mockito will upgrade and take it in account ?