question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InjectMocks doesn't re-inject new mocks to final fields when constructor injection is used

See original GitHub issue

Hello,

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:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
mryan43commented, Mar 3, 2022

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 :

  @BeforeMethod
  public void prepare() {
      testee=null; // mockito issue #1389
      MockitoAnnotations.initMocks(this);
  }
0reactions
guillaumeyancommented, Aug 19, 2018

With jUnit 5 it became possible to launch test lifecycle by class. Does mockito will upgrade and take it in account ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mockito, @InjectMocks strange behaviour with final fields
1 Answer 1 ... You are using the @InjectMocks for constructor incjection. This will work as long as Mockito finds the field not...
Read more >
Mockito @InjectMocks - Mocks Dependency Injection
Field Based - if there are no constructors or field-based injection possible, then mockito tries to inject dependencies into the field itself.
Read more >
Mockito: Why You Should Not Use InjectMocks Annotation to ...
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below.
Read more >
Annotation Magic with Mockito: InjectMocks - Encora
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection, in order. If any of the following...
Read more >
InjectMocks (Mockito 3.3.3 API) - Javadoc.io
Annotation Type InjectMocks ... Mark a field on which injection should be performed. ... Mockito will try to inject mocks only either by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found