How to use Mockito with JUnit 5?
Asked Answered
P

5

220

How can I use injection with Mockito and JUnit 5?

In JUnit 4, I can just use the @RunWith(MockitoJUnitRunner.class) annotation.
In JUnit 5, there is no @RunWith Annotation.

Pyromagnetic answered 4/12, 2016 at 16:50 Comment(0)
T
330

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.

Troublemaker answered 4/12, 2016 at 19:53 Comment(6)
There is now an official Mockito Junit5 Extension that is the equivalent to the MockitoJUnitRunner -> mockito-junit-jupiterMarianmariana
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/…Ergograph
Does the method annotated with @Test needs to be public or "package private" is good enough?Upton
When running tests with Jupiter (often referred to as "JUnit 5"), test methods only need to be package-visible.Troublemaker
Coming back to this - is there a preferred way? Any recommendations? Or is it opinion based?Utter
To my knowledge, no approach has became the accepted default.Troublemaker
N
90

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

    ...
}
Nuno answered 4/4, 2018 at 16:17 Comment(3)
@ExtendWith(MockitoExtension.class) is equivalent of @RunWith(MockitoJUnitRunner.class) of the JUnit4Irs
Can I do multiple calls of the method with different return values on a Mock object's method using MockitoExtension.class in JUnit5Augustinaaugustine
@RajHassani Yes you can, see here.Nuno
E
14

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.

Entoil answered 27/12, 2017 at 17:54 Comment(4)
why doesn't mockito-junit-jupiter pull the proper version of junit-jupiter-api?Venus
@Venus 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.Entoil
MockitoExtension doesn't appear to exist in mockito-core version 3.0.0.Deliladelilah
@Deliladelilah This is defined in mockito-junit-jupiterEntoil
P
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.

Pyromagnetic answered 4/12, 2016 at 16:50 Comment(2)
Link is broken, Page not foundEsp
The extension already exists, see other answersAnthropometry
F
1

For Kotlin and when annotating a field, make sure to mark it with lateinit:

@ExtendWith(MockitoExtension.class)
class MyTest {
    @Mock
    lateinit var list: List

    @Test
    fun `Test should work`() {
        list.add(100)
    }
}
Furfural answered 15/9, 2023 at 5:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.