How to use Mockito with JUnit5
JavaUnit TestingMockitoJunit5Java Problem Overview
How can I use injection with Mockito and JUnit 5?
In JUnit4 I can just use the @RunWith(MockitoJUnitRunner.class)
Annotation. In JUnit5 is no @RunWith
Annotation?
Java Solutions
Solution 1 - Java
There are different ways to use Mockito - I'll go through them one by one.
Manually
Creating mocks manually with Mockito::mock
works regardless of the JUnit version (or test framework for that matter).
Annotation Based
Using the @Mock-annotation and the corresponding call to MockitoAnnotations::initMocks
to create mocks works regardless of the JUnit version (or test framework for that matter but Java 9 could interfere here, depending on whether the test code ends up in a module or not).
Mockito Extension
JUnit 5 has a powerful extension model and Mockito recently published one under the group / artifact ID org.mockito : mockito-junit-jupiter.
You can apply the extension by adding @ExtendWith(MockitoExtension.class)
to the test class and annotating mocked fields with @Mock
. From MockitoExtension
's JavaDoc:
@ExtendWith(MockitoExtension.class)
public class ExampleTest {
@Mock
private List list;
@Test
public void shouldDoSomething() {
list.add(100);
}
}
The MockitoExtension documentation describes other ways to instantiate mocks, for example with constructor injection (if you rpefer final fields in test classes).
No Rules, No Runners
JUnit 4 rules and runners don't work in JUnit 5, so the MockitoRule
and the Mockito runner can not be used.
Solution 2 - Java
Use Mockito's MockitoExtension
. The extension is contained in a new artifact mockito-junit-jupiter
:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
It allows you to write tests as you would have with JUnit 4:
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
@ExtendWith(MockitoExtension.class)
class MyTest {
@Mock
private Foo foo;
@InjectMocks
private Bar bar; // constructor injection
...
}
Solution 3 - Java
There are different ways to do but the cleaner way and that also respects the JUnit 5 philosophy is creating a org.junit.jupiter.api.extension.Extension
for Mockito.
-
Creating mocks manually makes lose the benefit of additional Mockito checks to ensure you use correctly the framework.
-
Calling
MockitoAnnotations.initMocks(this)
in every test classes is boiler plate code that we could avoid.
And making this setup in an abstract class is not a good solution either.
It couples every test classes to a base class.
If then you need a new base test class for good reasons, you finish with a 3- level class hierarchy. Please avoid that. -
Test Rules is a JUnit 4 specificity.
Don't even think of that.
And the documentation is clear about that :
> However, if you intend to develop a new extension for JUnit 5 please > use the new extension model of JUnit Jupiter instead of the rule-based > model of JUnit 4.
- Test Runner is really not the way to extend the JUnit 5 framework.
JUnit 5 simplified the hell of the Runners of JUnit 4 by providing an extension model for writing tests thanks to JUnit 5 Extensions.
Don't even think of that.
So favor the org.junit.jupiter.api.extension.Extension
way.
EDIT : Actually, Mockito bundles a jupiter extension : mockito-junit-jupiter
Then, very simple to use :
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class FooTest {
...
}
Here is an addition to the excellent answer of Jonathan.
By adding as dependency the mockito-junit-jupiter
artifact, the use of @ExtendWith(MockitoExtension.class)
produced the following exception as the test is executed :
> java.lang.NoSuchMethodError: > org.junit.platform.commons.support.AnnotationSupport.findAnnotation(Ljava/util/Optional;Ljava/lang/Class;)Ljava/util/Optional;
THe problem is that mockito-junit-jupiter
depends on two independent libraries.
For example for mockito-junit-jupiter:2.19.0
:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.1.0</version>
<scope>runtime</scope>
</dependency>
The problem was I used junit-jupiter-api:5.0.1
.
So as junit-jupiter-api
moves still often in terms of API, make sure you depend on the same version of junit-jupiter-api
that mockito-junit-jupiter
depends on.