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?
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.
@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.
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.
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 ...
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
.
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,
This is considered bad practice because,
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:
@InjectMocks
@Mock
@Mock
s in the @InjectMocks
variable's fields (or call its constructors or use its setters - it depends on what kind of Dependency Injection you use)The three code samples below should be equivalent.
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!"));
}
}
.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!"));
}
}
@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!"));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With