Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually instantiating the @InjectMock annotated field

I have gone through some of the blogs in order to understand the basics of how Mockito annotations work.

However I am facing a doubt as to when does one go for manually instantiating the field annotated with @InjectMocks i.e

@InjectMocks
A a = new A();

And when does one rely on MockitoAnnotations.initMocks() functionality to do the same :

@InjectMocks
A a;

Does this depend on the JunitTestRunner that we employ to run the test cases or is it dependent on the Mockito framework version?

like image 595
lakshaya agnani Avatar asked Oct 28 '15 17:10

lakshaya agnani


People also ask

Why you should not use InjectMocks?

You shouldn't use InjectMocks to deal with injecting private fields (err..or at all) , because this kind of Dependency Injection is evil – and signals you should change your design.

What does InjectMocks annotation do?

@InjectMocks is the Mockito Annotation. It allows you to mark a field on which an injection is to be performed. Injection allows you to, Enable shorthand mock and spy injections.

How do you mock an Autowired field?

It uses field level annotations: @InjectMocks - Instantiates testing object instance and tries to inject fields annotated with @Mock or @Spy into private fields of testing object. @Mock - Creates mock instance of the field it annotates. @Spy - Creates spy for instance of annotated field.

Should we use @InjectMocks?

Regarding the underlying question: you probably should not use @InjectMocks; one of its core problems is: if injecting fails, Mockito does not report an error to you. In other words: you have passing unit tests, and some internal detail about a field changes ... and your unit tests break; but you have no idea why ...


2 Answers

In general, the decision to instantiate an object which is annotated with @InjectMocks or not is a code style choice. In the majority of cases there will be no difference as Mockito is designed to handle both situations.

However, there is some differences which I have outlined below.

@InjectMocks decouples a test from changes to the constructor.

In the same way using a Dependency Injection framework decouples your production code from changes to the constructor. Allowing Mockito to instantiate an instance of the class for you decouples your test code from changes to the constructor. This means any future changes to the class constructor can be done without causing compilation errors in the unit test.

In my opinion this is the biggest difference and the biggest advantage of @InjectMocks.

Mockito will always call the "biggest" constructor

Note: This difference is only relevant when the code you are working with does not follow best practices.

When there is multiple constructors in a class, Mocktio will call the constructor with the most parameters, the "biggest" constructor.

This only has an impact when,

  1. A "small" constructor contains logic.
  2. This logic is required for the class to function correctly.
  3. The "biggest" constructor does not invoke the next "smallest" constructor.

This is considered bad practice because,

  1. Placing logic within a constructor should be avoided whenever possible.
  2. When there is multiple constructors within a class each constructor should first invoke the constructor before it.
like image 95
fluffy88 Avatar answered Oct 10 '22 11:10

fluffy88


It depends if you are using (declaring) the runner or not.

If you use the runner, you don't need to call MockitoAnnotations.initMocks() yourself - the runner calls it for you.

Usually we go for the runner. When you want to use other runners, though (like Spring's), you can call .initMocks() yourself.

Just to be clear, the MockitoAnnotations.initMocks(this) will:

  • Instantiate the field annotated with @InjectMocks
  • Create a mock version of every field annotated with @Mock
  • Inject the @Mocks in the @InjectMocks variable's fields (or call its constructors or use its setters - it depends on what kind of Dependency Injection you use)

Mockito runner, initMocks and rule code samples

The three code samples below should be equivalent.

With runner:

This first snippet uses the runner, making the call to initMocks() unnecessary.

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}

Without runner + with manual call to .initMocks():

This other does not use the runner, thus the need for the setUp() method calling our initMocks() friend.

// notice there is no runner
public class MyClassTest {

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    // but now you have to call initMocks() yourself
    @Before
    public void setUp() throws Exception {
          MockitoAnnotations.initMocks(this);
    }

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}

Without runner or manual call, using @Rule:

Finally, as pointed out in the comments (thanks @StefanBirkner), since version 1.10.17, there is also the possibility of using a JUnit @Rule called MockitoRule:

public class MyClassTest {

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Mock private MyDependency myDependency;
    @InjectMocks private MyClass myClass;

    @Test
    public void myClass_should_get_stuff_from_dependency() {
        when(myDependency.getStuff()).thenReturn("stuff!");

        assertThat(myClass.getDependencyStuff(), is("stuff!"));
    }
}
like image 12
acdcjunior Avatar answered Oct 10 '22 13:10

acdcjunior