Cómo usar Mockito con JUnit5

103

¿Cómo puedo usar la inyección con Mockito y JUnit 5?

En JUnit4 solo puedo usar la @RunWith(MockitoJUnitRunner.class)Anotación. ¿En JUnit5 no hay @RunWithanotación?

Daniel Käfer
fuente

Respuestas:

145

Hay diferentes formas de usar Mockito; las revisaré una por una.

A mano

Crear simulacros manualmente con Mockito::mocktrabajos independientemente de la versión de JUnit (o marco de prueba para el caso).

Basado en anotaciones

Usando la anotación @Mock y la llamada correspondiente a MockitoAnnotations::initMocks para crear simulacros funciona independientemente de la versión de JUnit (o el marco de prueba para el caso, pero Java 9 podría interferir aquí, dependiendo de si el código de prueba termina en un módulo o no).

Extensión Mockito

JUnit 5 tiene un modelo de extensión poderoso y Mockito publicó recientemente uno bajo el ID de grupo / artefacto org.mockito : mockito-junit-jupiter .

Puede aplicar la extensión agregando @ExtendWith(MockitoExtension.class)a la clase de prueba y anotando campos simulados con @Mock. De MockitoExtensionJavaDoc:

@ExtendWith(MockitoExtension.class)
public class ExampleTest {

    @Mock
    private List list;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }

}

La documentación de MockitoExtension describe otras formas de crear instancias de simulacros, por ejemplo, con inyección de constructor (si rpefer campos finales en clases de prueba).

Sin reglas, sin corredores

JUnit 4 reglas y los corredores no funcionan en JUnit 5, por lo que el MockitoRuley el corredor Mockito no se pueden utilizar.

Nicolai
fuente
6
Ahora hay una extensión oficial de Mockito Junit5 que es el equivalente a MockitoJUnitRunner -> mockito-junit-jupiter
dan carter
Cuando se lanzó la extensión oficial de Mockito, escribí una publicación de blog con más detalles sobre cómo configurarla y usarla: solidsoft.wordpress.com/2018/03/27/…
Marcin Zajączkowski
¿El método anotado con @Testnecesidades debe ser público o el "paquete privado" es suficientemente bueno?
Geek
Al ejecutar pruebas con Jupiter (a menudo denominado "JUnit 5"), los métodos de prueba solo deben ser visibles en el paquete.
Nicolai
57

Utilice Mockito's MockitoExtension. La extensión está contenida en un nuevo artefactomockito-junit-jupiter :

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>2.23.4</version>
    <scope>test</scope>
</dependency>

Te permite escribir pruebas como lo harías con 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

    ...
}
Jonathan
fuente
6
@ExtendWith(MockitoExtension.class)es equivalente @RunWith(MockitoJUnitRunner.class)al JUnit4
Sergey Nemchinov
9

Hay diferentes formas de hacerlo pero la forma más limpia y que además respeta la filosofía JUnit 5 es crear un org.junit.jupiter.api.extension.Extension para Mockito.

1) Crear simulacros manualmente hace perder el beneficio de verificaciones adicionales de Mockito para asegurarse de que utiliza correctamente el marco.

2) Llamar MockitoAnnotations.initMocks(this)a todas las clases de prueba es un código de placa de caldera que podríamos evitar.
Y hacer esta configuración en una clase abstracta tampoco es una buena solución.
Acopla todas las clases de prueba a una clase base.
Si luego necesita una nueva clase de prueba base por buenas razones, termina con una jerarquía de clases de 3 niveles. Por favor evítelo.

3) Test Rules es una especificidad de JUnit 4.
Ni siquiera pienses en eso.
Y el documentación es clara al respecto:

Sin embargo, si tiene la intención de desarrollar una nueva extensión para JUnit 5, utilice el nuevo modelo de extensión de JUnit Jupiter en lugar del modelo basado en reglas de JUnit 4.

4) Test Runner no es realmente la forma de extender el marco JUnit 5.
JUnit 5 simplificó el infierno de los Runners de JUnit 4 al proporcionar un modelo de extensión para escribir pruebas gracias a JUnit 5 Extensions.
Ni siquiera pienses en eso.

Así que favorece el org.junit.jupiter.api.extension.Extensioncamino.


EDITAR: En realidad, Mockito incluye una extensión de júpiter: mockito-junit-jupiter

Entonces, muy simple de usar:

import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class FooTest {
     ...    
}

Aquí hay una adición a la excelente respuesta de Jonathan.

Al agregar como dependencia el mockito-junit-jupiterartefacto, el uso de @ExtendWith(MockitoExtension.class)produjo la siguiente excepción a medida que se ejecuta la prueba:

java.lang.NoSuchMethodError: org.junit.platform.commons.support.AnnotationSupport.findAnnotation (Ljava / util / Optional; Ljava / lang / Class;) Ljava / util / Optional;

El problema es que mockito-junit-jupiterdepende de dos bibliotecas independientes. Por ejemplo para 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>

El problema fue que usé junit-jupiter-api:5.0.1 .

Entonces, como junit-jupiter-apitodavía se mueve a menudo en términos de API, asegúrese de depender de la misma versión de la junit-jupiter-apique mockito-junit-jupiterdepende.

davidxxx
fuente
¿por qué no mockito-junit-jupitersaca la versión adecuada de junit-jupiter-api?
haelix
@haelix Porque la estrategia de versión utilizada para esta dependencia se basa en la biblioteca Mockito. Mira la versión aquí mockito-junit-jupiter:2.19.0. Mientras que las versiones de JUnit Jupiter comienzan con 5. mockito-junit-jupiter debería haber especificado en su identificador de artefacto las dos cosas (la versión de Mockito y la versión de JUnit Jupiter) para aclarar las cosas. Por ejemplo, mockito-junit-jupiter-5.1:2.19.0para transmitir que la biblioteca está diseñada para JUnit Jupiter 5.1.
davidxxx
MockitoExtensionno parece existir en la mockito-coreversión 3.0.0.
Thunderforge
1
@Thunderforge Esto se define enmockito-junit-jupiter
davidxxx
3

Tienes que usar la nueva @ExtendWithanotación.

Lamentablemente, aún no hay una extensión publicada. En github puedes ver una implementación beta para la extensión. como ejemplo de prueba de demostración .

Daniel Käfer
fuente