beatngu13
beatngu13

Reputation: 9393

Mock autowired dependency in JUnit 5 test for Spring Boot 2 app

Consider the following class under test:

public class SomeClass {

    @Autowired
    private SomeDependency someDependency;

    public int inc(int i) {
        someDependency.doSomething();
        return i + 1;
    }

}

How can I mock (preferably with Mockito) someDependency in a JUnit 5 (5.0.1) test for a Spring Boot 2 (2.0.0.M2) application? When I try to invoke SomeClass#inc(int) it yields a NullPointerException because the autowired dependency isn't injected.

Upvotes: 8

Views: 13488

Answers (1)

davidxxx
davidxxx

Reputation: 131466

Mockito 1 runner (MockitoJUnitRunner class) is not designed to run JUnit 5 tests.

So annotating your class with :

import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class) 
public class MyJUnit5Test {

will have no effect.

To be able to use the @Mock annotation, you could invoke before each test :

 MockitoAnnotations.initMocks(this);

in a method annotated with JUnit 5 @BeforeEach.
But from now a better alternative to not repeat this pre-processing in each JUnit test class is using the MockitoExtension class provided by the mockito-junit-jupiter dependency.


Code example

Supposing the SomeDependency class declared as :

@Component
public class SomeDependency {

    public String returnThat() {
        return "that";
    }
}

You could so mock the dependency in this way in your unit test :

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

import davidhxxx.example.angularsboot.SomeDependency;

@ExtendWith(MockitoExtension.class)    
public class SomeClassTest {

    @Mock
    SomeDependency someDependencyMock;

    private SomeClass someClass;

    @BeforeEach
    public void setup(){
      someClass = new SomeClass(someDependencyMock);
    }

    @Test 
    void myFirstTest() {
      Mockito.when(someDependencyMock.returnThat()).thenReturn("mock result");
      Assertions.assertEquals("mock result", someClass.inc());
    }

}

Note that SomeClass has to provide a way to set its SomeDependency dependency.
You should add a constructor that accepts an instance of.
Using setter is also a way while it provides mutability.


pom.xml requirements

1) You can add the spring-boot-starter-test dependency that includes Mockito and other useful things in inherited dependencies :

<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
   ...
</dependencies>

Add also the junit-jupiter-engine dependency and all other optional JUnit 5 dependencies that you require :

<dependencies>
    ...
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-junit-jupiter</artifactId>
        <version>2.18.0</version> <!-- version to specify as not provided by Spring Boot dependencies -->
        <scope>test</scope>
    </dependency>
</dependencies>

You don't need to specify version for the junit-jupiter-engine artifact but you may need for other JUnit 5 dependencies such as junit-jupiter-params.
Hoping that this would be not required any longer in next versions of Spring Boot.

2) Beware : if you use a Spring Boot version that pulls the 2.20 version of the maven-surefire-plugin it will not work. So you will have to override the maven-surefire-plugin plugin configuration to specify a version compatible with JUnit 5 (that is 2.19 or 2.21 and later).
For example the 2.0.0.M5 version of Spring Boot pulls maven-surefire-plugin:2.20 and so reconfiguring the plugin such as the following is required :

    <plugins>
        ...
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19</version>
            <dependencies>
                <dependency>
                    <groupId>org.junit.platform</groupId>
                    <artifactId>junit-platform-surefire-provider</artifactId>
                    <version>1.0.0</version>
                </dependency>
            </dependencies>
        </plugin>
     ...
   <plugins>

It will generate a Maven warning :

Overriding managed version 2.20.1 for maven-surefire-plugin

Good news : from the 2.0.1.RELEASE version of Spring Boot this issue is solved as the maven-surefire-plugin version was updated to use 2.21.0 and later version that solves the issue.

Upvotes: 6

Related Questions