When writing your Java unit test you will soon need a way to handle the dependencies of your classes under test. Mockito have some nice features that simplify the creation and usage of mock objects that have improved gradually during the last couple of years.
Class under test
Imagine that you write an Example
class that has a Delegate
dependency. It may be implemented as a POJO with constructor injection:
Alternatively, it could be rewritten using setter injection based on Java EE 6 / JSR 330 annotations:
It could also be a Spring bean based on field injection:
There are more ways to refactor this class, but you get the point.
The Mockito way
It turns out that all these examples can be verified using the same Mockito test:
The interesting part of this test is the code that is not there. You may be surprised to find that the test does not contain the traditional boilerplate code associated with jUnit tests such as a @Before
method, there is no new Example()
call that instantiates the class under test, nor any application context from which an example bean can be obtained. Moreover, there is no call to the mock() method to create the delegate mock object. Despite all this, an Example
instance will be created, a mock object will be injected into it, and the test will execute and pass.
When the MockitoJUnitRunner executes the test, Mockito creates mocks and spies instances for all fields that are annotated with the @Mock or the @Spy annotations. Next, the field declaration that is annotated with the @InjectMocks annotation is instantiated and Mockito injects the mocks and spies into it. This occurs before each test method, so there is no there is no residual state left from any previous test that may affect the current test. From this part onwards, the test behaves like any other test and you can write your assertions and verifications as usual.
As can be seen from the above examples, Mockito supports dependency injection by using constructor arguments, setter methods and field injection. The underlying implementation relies on reflection, which means that there is no dependency on the Java EE 6 or Spring annotations as far as Mockito is concerned (obviously, you will get a compile error if you do not add the corresponding dependencies to the class path and your application will fail if there is no matching bean definition in runtime, but that has nothing to do with the unit test).
Limitations
There are some things you should be aware of when you are writing test this kind of test, such as
- The order of which the dependency injection is attempted is constructor injection, setter injection and lastly field injection.
- Only one dependency injection strategy will occur for each test case. For example, if a suitable constructor is found, neither the setter injection nor the field injection will come to play.
- Mockito does not report if any dependency injection strategy fails.
- For constructor injection the “biggest” constructor is chosen, and
null
will be passed as argument for dependencies that are neither mocks nor spies. - Fields may not be declared as
final
orstatic
(butprivate
fields are supported).
Please read the documentation of the @InjectMocks to learn about the details.
Dependency
Mockito 1.9.0
Thanks good post!
Thank you!
Thanks, this is exactly what I was looking for!
No worries, glad to help!
Hi,
thanks for the good post.
The Needle Framework (http://needle.spree.de) allows simple testing of Java EE component, such as CDI or EJB. Needle analyze the dependencies and injects automatic mock objects. It is well integrated with Mockito and EasyMock.
Regards, Heinz
Thanks for the tip, I did not know about Needle before.
Cheers, Mattias
I am trying to follow your example, only using IWorkbench.
My class under test:
********************
@Named(“example”)
public class MyClass implements YetAnotherClass {
@Inject private IWorkbench workbenchContext;
public final void myMethod() {
workbenchContext.getClass().getName(); // Null Ptr
// Exception @ runtime
}
}
And in the test case:
*********************
@RunWith(MockitoJUnitRunner.class)
public class TestClass extends YetAnotherTestClass {
@Mock private IWorkbench workbenchContextMock;
@InjectMocks private MyClass example;
public static Test suite() throws NoSuchFieldException,
SecurityException {
TestSuite testSuite = new TestSuite();
testSuite.addTest(new JUnit4TestAdapter(
MyClass.class));
return testSuite;
}
}
I am running Eclipse Juno 4.2.1 with Java 7.
May I ask if you see anything wrong with the above structure?
Thank you, Theresa
I have figured it out. It was solved by understanding the order of injection and also which MyClass should be instantiated by the JUnit test.
Thank you very much, though, for this example. It very much helped!
Theresa
@Theresa: Good that you solved your problem and that you found my blog post helpful!
Super helpful! Thank you for the post.
@Sandeep: Thanks, glad to help.