Dobles de test en JUnit 4\5 con Mockito

Última actualización: 13/12/2022
mockito

No soy un gran seguidor del cine de acción, pero es innegable que película tras película James Bond se supera. No importa quien sea el intérprete. Lo mismo salta de una presa que se lanza en paracaídas, atraviesa a toda velocidad las calles de Roma o desciende esquiando la montaña más escarpada mientras se deshace con elegancia de los esbirros de turno.

¿El truco? Los dobles de acción. Estos asombrosos profesionales reemplazan al actor en las escenas complicadas que no puede hacer, o bien resultan demasiado peligrosas. En última instancia, los dobles digitales podrán con todo.

  1. El problema a resolver
  2. Proyecto de ejemplo
  3. Crear objetos mock
    1. Con Mockito#mock
    2. Con la anotación @Mock
  4. Definir el comportamiento de los métodos
    1. when…then
    2. do..when
  5. El error UnnecessaryStubbingException
  6. La anotación @InjectMocks
  7. Modificar objetos reales con @Spy
  8. Comprobar llamadas a métodos con verify
  9. BDDMockito
  10. Cómo «mockear» métodos estáticos
  11. Integración con Spring Boot
  12. Código de ejemplo

El problema a resolver

El ejemplo anterior es una buena metáfora para dar forma física al concepto doble de test (test double). Se trata de objetos que reemplazan a los objetos reales de la aplicación en aquellas pruebas en las que deben hacer cosas inusuales para las que no están preparados.

Esta figura ilustra el concepto con un caso habitual.

Queremos probar una clase de manera aislada en un test unitario veloz como un rayo. El inconveniente es que usa una clase que interacciona con una base de datos. Esto supone dos grandes dificultades:

  • Necesitamos que la base de datos esté disponible.
  • La base de datos debe ofrecer para cada prueba un juego de datos adecuado que nos permita probar lo que queremos.

En realidad, lo anterior no es un problema cuando hacemos pruebas de integración porque el empleo de la base de datos es uno los elementos a testear. Si usas Spring Boot, todo esto lo explico en este tutorial:

Sea como fuere, volvamos al ejemplo. ¿La solución? Un doble que haga lo que necesitemos en cada momento. Y, por supuesto, que no llame a la base de datos.

Si la clase DAO implementa una interfaz, crear los dobles es sencillo; pero resultará tedioso y con frecuencia terminaremos creando una miríada de clases. ¿Y qué pasa con los métodos estáticos? Problemón a la vista.

Con la librería de código abierto Mockito es posible modificar el comportamiento de métodos concretos de un objeto o crear dobles de tests al completo sin tener que escribir ni una sola clase.

Mockito es el héroe de acción que necesitamos. ¡Ni siquiera los métodos estáticos se interponen en su camino! En este tutorial te muestro sus principales poderes.

Proyecto de ejemplo

El proyecto de ejemplo, disponible en GitHub, consiste en un proyecto Maven para Java 8 que permite ejecutar pruebas con la plataforma JUnit 5. Las escribiremos con las librerías Jupiter (son las pruebas comúnmente conocidas como tests de JUnit 5) y Vintage (soporte de pruebas de JUnit 4 sobre JUnit 5). Mi objetivo es que veas cómo usar Mockito en ambos casos.

Para añadir Mockito a un proyecto solo se requiere una dependencia:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>

En cuanto a JUnit 5, las dependencias son junit-jupiter (Jupiter) y junit-vintage-engine (Vintage-JUnit 4):

<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter</artifactId>
	<version>${junit.version}</version>
	<scope>test</scope>
</dependency>

<dependency>
	<groupId>org.junit.vintage</groupId>
	<artifactId>junit-vintage-engine</artifactId>
	<version>${junit.version}</version>
	<scope>test</scope>
</dependency>

Vamos a jugar con las posibilidades de Mockito testeando un par de clases muy sencillas y relacionadas entre sí:

package com.danielme.blog.testdouble;
 
public class Dependency {
 
    private final SubDependency subDependency;
 
    public Dependency(SubDependency subDependency) {
        super();
        this.subDependency = subDependency;
    }
 
    public String getClassName() {
        return this.getClass().getSimpleName();
    }
 
    public String getSubdepedencyClassName() {
        return subDependency.getClassName();
    }
 
    public int addTwo(int i) {
        return i + 2;
    }
 
    public String getClassNameUpperCase() {
        return getClassName().toUpperCase();
    }
 
}
package com.danielme.blog.testdouble;
 
public class SubDependency {
 
    public String getClassName() {
        return this.getClass().getSimpleName();
    }
}

Crear objetos mock

Empecemos construyendo una clase con pruebas en la que modificaremos sobre la marcha el comportamiento de los métodos de Dependency.

Necesitamos un mock de Mockito para la clase Dependency: un objeto que simule ser un Dependency. Será nuestro doble de test. Contamos con dos alternativas.

Nota. Merece la pena señalar que Mockito admite clases finales e interfaces. ¡Ahí es nada!

Con Mockito#mock

Invocaremos el método Mockito.mock para crear un objeto mockk de cierta clase:

Dependency dependency = Mockito.mock(Dependency.class)
Con la anotación @Mock

Declaramos la clase cuyo comportamiento queremos redefinir en un atributo anotado con @Mock:

@Mock 
private Dependency dependency;

Tenemos que conseguir que Mockito instancie los objetos anotados con @Mock antes de la ejecución de cada prueba. La idea es que en cada una de ellas tengamos un objeto mock virgen que modificaremos a nuestro antojo:

@Before 
public void setupMock() { MockitoAnnotations.openMocks(this); 

Es posible automatizar la operación anterior en función de la versión de JUnit que usemos.

En JUnit 4 contamos con la regla MockitoRule:

@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();

En su lugar, podemos usar un runner:

@RunWith(MockitoJUnitRunner.class)
public class DependencyMockTest {

Dado que solo se puede aplicar un runner a una clase, lo cual supone una limitación, es preferible usar la regla.

Por su parte, en JUnit 5 (pruebas escritas con la librería Jupiter) tenemos la extensión MockitoExtension, disponible en el artefacto mockito-junit-jupiter. Con su dependencia no hace falta declarar mockito-core porque ya está implícita:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>
@ExtendWith(MockitoExtension.class)
public class JupiterTest {

Jupiter permite el paso de argumentos a las pruebas, así que podemos hacer lo siguiente:

@Test
public void hasLocalMockInThisTest(@Mock Dependency dependency) {
   ...
}

Sea cual sea la opción elegida —en el proyecto de ejemplo las encontrarás todas—, ya tenemos en el atributo dependency una instancia de tipo mock lista para ser utilizada. Si inspeccionas ese objeto con un depurador, verás que es un proxy, técnica empleada en marcos de trabajo tan importantes como Spring, Hibernate o Jakarta CDI.

En el código no veremos diferencia alguna entre el objeto proxy y el objeto al que representa. El señor Bond y sus dobles serán físicamente indistinguibles, aun en los planos más cercanos.

Definir el comportamiento de los métodos

Las llamadas a los métodos del mock de Dependency no harán nada. Si el método retorna un objeto, será null. Si el resultado fuera un tipo primitivo (boolean, int…), se devuelve su valor predeterminado (false, 0…). Esta prueba lo corrobora:

@Mock
private Dependency dependency;

@Test
public void testDummy() {
    assertNull(dependency.getClassName());
    assertNull(dependency.getClassNameUpperCase());
    assertNull(dependency.getSubdependencyClassName());
    assertEquals(0, dependency.addTwo(2323));
}

Nota. Si quieres escribir con facilidad aserciones potentes te recomiendo la libreria AssertJ. La uso en todos mis proyectos.

Lo más probable es que este objeto dependency nos sirva de poco en su estado actual…

when…then

La diversión empieza ahora. Mira esta prueba:

@Test
public void testDependency() {      
    Mockito.when(dependency.getClassName()).thenReturn("hi there");
 
    assertEquals("hi there", dependency.getClassName());
}

La API es tan intuitiva que el código no requiere de grandes explicaciones. La línea tres se lee así: cuando se invoque al método getClassName del objeto dependency, se debe devolver la cadena «hi there». Todo ello con una sola línea de código gracias al método estático when.

También se puede forzar el lanzamiento de una excepción con thenThrow:

@Test(expected = IllegalArgumentException.class)
public void testException() {       
    when(dependency.getClassName()).thenThrow(IllegalArgumentException.class);
 
    dependency.getClassName();
}

Si el método recibe parámetros, debemos especificar el conjunto de valores para los que se devolverá el resultado que estamos definiendo:

@Test
public void testAddTwo(){       
    when(dependency.addTwo(1)).thenReturn(5);
 
    assertEquals(5, dependency.addTwo(1));  
    assertEquals(0, dependency.addTwo(27));
}

En la anterior prueba indicamos que cuando se invoque addTwo con el valor 1 se devuelva 5. Para el resto de valores, el método no hace nada. Por ello, en la segunda aserción responde con 0 por ser el tipo de retorno un entero.

Los numerosos métodos de ArgumentMatchers permiten definir con gran flexibilidad los parámetros de entrada:

@Test
public void testAddTwoAny(){        
    when(dependency.addTwo(anyInt())).thenReturn(2);
 
    assertEquals(2, dependency.addTwo(3));      
    assertEquals(2, dependency.addTwo(80));
}

En esta ocasión, addTwo devuelve dos. No nos importa su argumento; aceptamos cualquier entero (anyInt).

No estamos limitados a devolver un valor prefijado. Podemos escribir el código para cualquier método en una implementación de la interfaz Answer y usarla como argumento de thenAnswer. En este ejemplo se define un comportamiento para addTwo consistente en adicionar a su entrada veinte unidades en vez de dos:

@Test
public void testAnswer() {
when(dependency.addTwo(anyInt())).thenAnswer(new Answer<Integer>() {
 
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            int arg = (Integer) invocation.getArguments()[0];
            return arg + 20;
        }
    });
 
assertEquals(30, dependency.addTwo(10));        
}

El argumento de Answer es de tipo InvocationOnMock, una interfaz que modela la llamada realizada al método que estamos simulando. En la línea seis se emplea para obtener el valor que se le dio al argumento del método simulado.

Answer solo tiene un método, por lo que podemos escribir una expresión lambda:

    @Test
    public void testAnswer() {
        when(dependency.addTwo(anyInt())).thenAnswer((Answer<Integer>) invocation -> {
            int arg = (Integer) invocation.getArguments()[0];
            return arg + 20;
        });

        assertEquals(30, dependency.addTwo(10));
    }
do..when

¿Y si un método no devuelve nada? Por ejemplo:

public void printMessage(String msg) {
    System.out.println(msg);
}

Los ejemplos que hemos visto son inútiles porque Mockito#when devuelve un objeto tipado para un resultado que ahora no existe.

El apaño rápido es hacer que el método retorne Void, pero no hay que llegar a este extremo. Lo que haremos es declarar el comportamiento del método a simular con los métodos de la clase Mockito que empiezan por do, equivalentes a los then. Estos do devuelven un objeto que cuenta con un método when en el que indicaremos el objeto mock. Por último, con el objeto retornado por ese when llamaremos al método a simular. El código final es una estructura con la forma do…when.

@Test
public void testVoidDoAnswer() {
    String msg = "hello";
 
    Mockito.doAnswer(invocation -> {
        Object arg0 = invocation.getArgument(0);
        assertEquals(msg, arg0);
        return null;
    }).when(dependency).printMessage(anyString());
 
    dependency.printMessage(msg);
}

El test define el comportamiento de printMessage con un Answer que debe retornar null porque printMessage no devuelve nada.

Este otro ejemplo de do…when lanza una excepción cuando printMessage sea llamado.:

@Test(expected = IllegalArgumentException.class)
public void testVoidException() {
    Mockito.doThrow(IllegalArgumentException.class)
                .when(dependency).printMessage(anyString());
    dependency.printMessage("");
}

La existencia de los métodos doAnswer y doReturn otorgan al formato do…when el carácter de universal, ya que sirve para métodos con y sin retorno:

when(dependency.addTwo(anyInt())).thenReturn(2);
doReturn(2).when(dependency).addTwo(anyInt());

Entonces, ¿por qué existe una opción más restrictiva como el when? En mi opinión, se debe a que otorga mayor semántica al código. Es más natural leer «cuando A entonces B» que «hacer B cuando A», del mismo modo que se suele usar while en lugar de do..while.

Si te sirve de ayuda, yo siempre utilizo when..then salvo en los dos casos en los que resulta imposible. Uno lo acabamos de ver (retorno void), el otro afecta a los objetos spy que examinaremos más adelante.

El error UnnecessaryStubbingException

El runner de JUnit 4 y la extensión de JUnit 5 / Jupiter lanzan una excepción si encuentran un método simulado que nunca se invoca:

org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected in test class: DependencyMockTest
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
at com.danielme.blog.testdouble.DependencyMockTest.testVoidDoAnswer(DependencyMockTest.java:86)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class. at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:53)

Si no fuera un error porque es algo que estamos haciendo de manera intencionada, tenemos que usar este runner:

@RunWith(MockitoJUnitRunner.Silent.class)

En el caso de la extensión aquí tienes la configuración:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)

La anotación @InjectMocks

Las pruebas anteriores nos han permitido ver el funcionamiento básico de Mockito. Pero si te fijas bien, no tienen sentido porque estamos emulando el código que queremos probar.

En una aplicación real, los dobles de test sustituirán a las dependencias de la clase que estamos probando. Un ejemplo más realista es el siguiente en el que validamos Dependency con un mock de SubDependency:

package com.danielme.blog.testdouble;
 
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
 
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
 
public class DependencyMockTest2 {
 
    @Mock
    private SubDependency subDependency;
    private Dependency dependency;
 
    @Before
    public void setupMock() {
        MockitoAnnotations.openMocks(this);
        dependency = new Dependency(subDependency); 
    }   
 
    @Test
    public void testSubdependency() {
        when(subDependency.getClassName()).thenReturn("hi there 2");    
 
        assertEquals("hi there 2", dependency.getSubdependencyClassName());
    }   
     
}

La prueba chequea que el método Dependency#getSubdependencyClassName() llama al mock de SubDependency.

Hemos construido el objeto a probar proporcionándole un @Mock. Esto nos lo ahorramos con la anotación @InjectMocks:

package com.danielme.blog.testdouble;
 
import static org.junit.Assert.*;
 
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
 
import com.danielme.blog.testdouble.SubDependency;
 
public class DependencyMockTest2 {
 
    @Mock
    private SubDependency subDependency;
    @InjectMocks
    private Dependency dependency;
 
    @Before
    public void setupMock() {
        MockitoAnnotations.openMocks(this);     
    }   
 
    @Test
    public void testSubdependency() {
        when(subDependency.getClassName()).thenReturn("hi there 2");    
     
        assertEquals("hi there 2", dependency.getSubdependencyClassName());
    }   
     
}

Ahora Mockito intenta crear Dependency llamando a su constructor con un mayor número de parámetros. Si tiene argumentos que no pueda reemplazar por un mock, usará null.

Suelo insistir en el blog de la importancia de pasar a un objeto todas las dependencias que necesita en el constructor: es la forma natural de crear un objeto con un estado inicial válido. No obstante, si aplicas @InjectMock a una clase sin un constructor con parámetros, Mockito intentará realizar la inyección de los mocks declarados en la prueba en los setters adecuados. Si esta estrategia tampoco funcionara, la inyección se intentará en los atributos.

Modificar objetos reales con @Spy

La alternativa a los mock son los objetos spy: todos sus métodos tienen el funcionamiento de un objeto real -el que podemos crear con new-, pero pueden cambiarse con when..then y do..when. Recuerda: los métodos de un mock no hacen nada, a menos que les demos un comportamiento.

Mockito no crea los objetos spy. Se obtienen a partir de un objeto real con @Spy, tal y como puedes ver en esta clase de prueba:

package com.danielme.blog.testdouble;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

public class DependencySpyTest {

	@Spy
	private Dependency dependency = new Dependency(new SubDependency());


	@Before
	public void setupMock() {
		MockitoAnnotations.openMocks(this);
	}

	@Test
	public void testOriginal() {
		assertEquals(7, dependency.addTwo(5));
	}

	@Test
	public void testSpy() {
		when(dependency.addTwo(Mockito.anyInt())).thenReturn(3);

		assertEquals(3, dependency.addTwo(27));
		assertEquals(SubDependency.class.getSimpleName(), dependency.getSubdependencyClassName());
	}

}

La prueba testOriginal asegura que el objeto dependency actúa como una instancia real de Dependency. En consecuencia, el método addTwo hace lo que tiene que hacer: sumar dos al argumento.

Por el contrario, testSpy cambia el comportamiento de addTwo. El resto de métodos, como getSubdepedencyClassName(), no se ven afectados y conservan su funcionamiento original.

El método estático Mockito#spy sirve de alternativa a @Spy:

Dependency dependency = Mockito.spy(new Dependency(new SubDependency()));

Comenté que había un escenario relativo a los objetos spy en el que resultaba más conveniente emplear el patrón do..when. Este método, perteneciente a Dependency, se ríe de nosotros lanzando siempre una excepción:

public String surpriseMe() {
    throw new RuntimeException("Ah-Ha!");
}

Démosle un comportamiento más educado:

@Test
public void testSurpriseMe(){
	when(dependency.surpriseMe()).thenReturn("I love you!!!");
}

Siendo dependency un spy, ¿qué sucederá si ejecutamos la prueba? Cabría esperar que nada, pues estamos simulando el método para que retorne una cadena. ¡Error! La excepción se sigue lanzando:

java.lang.RuntimeException: Ah-Ha!

	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710)
	at com.danielme.blog.testdouble.Dependency.surpriseMe(Dependency.java:33)

Resulta que dentro de when se está invocando al método real. Cuando esto sea un problema, usaremos do…when de la manera habitual:

@Test
public void testSurpriseMeDoWhen() {
	String niceSurprise = "I love you!!!";
	doReturn(niceSurprise).when(dependency).surpriseMe();

    assertEquals(niceSurprise, dependency.surpriseMe());
 }

Ahora, con do..when el método surpriseMe que se ejecuta ya tiene el comportamiento que le damos con doReturn.

Comprobar llamadas a métodos con verify

En la clase Mockito encontramos una aserción curiosa y más útil de lo que parece a simple vista. El método Mockito#verify «verifica» que un método de un mock o spy fue ejecutado cierto número de veces (cantidad exacta, como mínimo, como máximo, nunca…).

Esta clase muestra a modo de prontuario varios ejemplos:

package com.danielme.blog.testdouble;


import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class DependencyVerifyTest {

    @Mock
    private Dependency dependency;

    @Test
    void testSimpleVerify() {
        //nunca se ha ejecutado
        verify(dependency, never()).getClassNameUpperCase();

        dependency.getClassNameUpperCase();
        //exactamente una vez
        verify(dependency, times(1)).getClassNameUpperCase();
        //como mínimo una vez
        verify(dependency, atLeast(1)).getClassNameUpperCase();

        dependency.getClassNameUpperCase();
        //como máximo 2 veces
        verify(dependency, atMost(2)).getClassNameUpperCase();
    }

    @Test
    void testParameters() {
        dependency.addTwo(3);
        //una vez con el parámetro 3
        verify(dependency, times(1)).addTwo(3);

        dependency.addTwo(4);
        //dos veces con cualquier parámetro
        verify(dependency, times(2)).addTwo(anyInt());
    }

}

En mi tutorial Spring Framework: Sistema de eventos verás un caso de uso real de verify: comprobar que Spring ejecutó los oyentes (listeners) de un evento.

BDDMockito

Un patrón muy común a la hora de escribir pruebas es la estructura «dado X, cuando Y entonces Z», en inglés «given-when-assert». En given tenemos los elementos que precisa el test; When es la operación que queremos probar; con then comprobamos que todo ha ido bien. Esta estructura es promulgada por la metodología BDD (desarrollo guíado por el comportamiento o Behaviour Driven Development).

Si te animas a probarla —o te obligan—, Mockito te apoya con la clase BDDMockito.

@ExtendWith(MockitoExtension.class)
class BDDMockitoTest {

    @Mock
    private Dependency dependency;

    @Test
    void testDependency() {
        //given
        given(dependency.getClassName()).willReturn("hi there");

        //when
        
        //then
        assertEquals("hi there", dependency.getClassName());
    }
    
}

Hemos cambiado la estructura when…then por given..will. Sección when no tenemos y el then es una aserción de Jupiter.

BDDMockito también adapta a esta notación las verificaciones de verify con el patrón then..should.

@Test
void testVerify() {
    //given

    //when
    dependency.getClassNameUpperCase();

    //then
    then(dependency).should().getClassNameUpperCase();
    then(dependency).should(never()).getClassName();
}

Cómo «mockear» métodos estáticos

Una limitación histórica de Mockito era su incapacidad para simular métodos estáticos. Y bien pensando, no debería ser una restricción importante: si necesitamos esta funcionalidad, quizás estemos haciendo un mal uso de los métodos estáticos, de los cuales se suele abusar -me incluyo entre los pecadores-. Con todo, a veces no quedará más remedio que hacerlo.

La solución consistía en integrar Mockito con PowerMock. Hablo en pasado porque desde Mockito 3.4 (julio de 2020) contamos para estos menesteres con los métodos mockStatic.

Tomemos esta clase como referencia:

package com.danielme.blog.testdouble;
 
public final class BoolUtils {
 
    private BoolUtils() {}
 
    public static boolean isTrue(Boolean bool) {
        return bool != null && bool;
    }
}

BoolUtils es la típica clase de utilidades. Si bien no tiene sentido, vamos a simular el método isTrue para que siempre devuelva false; pero antes, debemos cambiar la dependencia mockito-core por mockito-inline:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>

Aquí tienes el ejemplo al completo:

package com.danielme.blog.testdouble;
 
import org.junit.Test;
import org.mockito.MockedStatic;
 
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mockStatic;
 
public class StaticMethodTest {
 
    @Test
    public void testStaticMocked() {
        try (MockedStatic<BoolUtils> utilsMocked = Mockito.mockStatic(BoolUtils.class)) {
            utilsMocked.when(() -> BoolUtils.isTrue(anyBoolean())).thenReturn(false);
 
            assertFalse(BoolUtils.isTrue(true));
            assertFalse(BoolUtils.isTrue(false));
            assertFalse(BoolUtils.isTrue(null));
       }
    assertTrue(BoolUtils.isTrue(true));
   }
     
}

El mock de la clase con el método estático es una instancia de MockedStatic obtenida en un bloque try-with-resources. Dentro construimos una estructura when..thenReturn un poco distinta a las que hemos visto hasta ahora. Primero se invoca al método when del objeto simulado (utilsMocked) para indicar el método a simular (isTrue). Fíjate que isTrue se llama sobre la clase BoolUtils en una expresión lambda (interfaz MockStatic.Verification). Luego encadenamos la consabida llamada a thenReturn.

La aserción de la línea 21 certifica que el nuevo comportamiento de BoolUtils#isTrue solo es válido dentro del bloque try.

Integración con Spring Boot

Si usas Spring Boot y programas tests que requieran del contexto de Spring, ¡enhorabuena! Cuentas en tu caja de herramientas con las anotaciones @MockBean y @SpyBean para convertir en objetos mock y spy los beans existentes en el contenedor de dependencias de Spring.

Una vez más, te recomiento este tutorial.

Código de ejemplo

El proyecto se encuentra en GitHub. Para más información sobre GitHub, consulta este artículo.

Otros tutoriales sobre testing

Testing con JUnit 4

Introducción al testing automatizado

Testing Spring con JUnit 4

JUnit 5

Testing en WildFly con Arquillian

Testing en Spring Boot con JUnit 4\5. Mockito, MockMvc, REST Assured, bases de datos embebidas.

Testing Spring Boot: Docker con Testcontainers y JUnit 5

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.