How to use Mockito with JUnit5

145,252

Solution 1

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

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

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.

1) Creating mocks manually makes lose the benefit of additional Mockito checks to ensure you use correctly the framework.

2) 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.

3) 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.

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.

Solution 4

You have to use the new @ExtendWith annotation.

Unfortunately there is no extension released yet. On github you can see a beta implementation for the extension. as a example demo test.

Share:
145,252

Related videos on Youtube

Daniel Käfer
Author by

Daniel Käfer

Updated on May 04, 2022

Comments

  • Daniel Käfer
    Daniel Käfer about 2 years

    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?

  • dan carter
    dan carter almost 6 years
    There is now an official Mockito Junit5 Extension that is the equivalent to the MockitoJUnitRunner -> mockito-junit-jupiter
  • haelix
    haelix over 5 years
    why doesn't mockito-junit-jupiter pull the proper version of junit-jupiter-api?
  • davidxxx
    davidxxx over 5 years
    @haelix Because the version strategy used for this dependency relies on Mockito library. Look at the version here mockito-junit-jupiter:2.19.0. While JUnit Jupiter versions start with 5. mockito-junit-jupiter should have specified in its artifact identifier the two things (Mockito version and JUnit Jupiter version) to make things clearer. For example mockito-junit-jupiter-5.1:2.19.0 to convey that the library is designed for JUnit Jupiter 5.1.
  • Thunderforge
    Thunderforge almost 5 years
    MockitoExtension doesn't appear to exist in mockito-core version 3.0.0.
  • davidxxx
    davidxxx almost 5 years
    @Thunderforge This is defined in mockito-junit-jupiter
  • Marcin Zajączkowski
    Marcin Zajączkowski about 4 years
    When the official extension for Mockito was released, wrote a blog post with more details how to configure and use it: solidsoft.wordpress.com/2018/03/27/…
  • Sergey Nemchinov
    Sergey Nemchinov almost 4 years
    @ExtendWith(MockitoExtension.class) is equivalent of @RunWith(MockitoJUnitRunner.class) of the JUnit4
  • Geek
    Geek almost 4 years
    Does the method annotated with @Test needs to be public or "package private" is good enough?
  • Nicolai Parlog
    Nicolai Parlog almost 4 years
    When running tests with Jupiter (often referred to as "JUnit 5"), test methods only need to be package-visible.
  • Raj Hassani
    Raj Hassani over 3 years
    Can I do multiple calls of the method with different return values on a Mock object's method using MockitoExtension.class in JUnit5
  • Jonathan
    Jonathan over 3 years
    @RajHassani Yes you can, see here.
  • Ermiya Eskandary
    Ermiya Eskandary over 2 years
    Coming back to this - is there a preferred way? Any recommendations? Or is it opinion based?
  • Nicolai Parlog
    Nicolai Parlog over 2 years
    To my knowledge, no approach has became the accepted default.