6

Pruebas usando Junit, Mockito, y MockMVC

Inspirado por una pregunta del usuario OBD7 sobre dónde encontrar información sobre JUnit, decidí hacer un pequeño post en donde haremos una prueba de integración y una prueba unitaria usando MockMVC y Junit. Antes de empezar es importante resaltar que probar nuestras aplicaciones es una parte vital de nuestro trabajo como programadores, ya que mediante las pruebas podemos estar más seguros de que lo hacemos está correcto, sirve como documentación para el futuro y además permite que nuestro sistema pueda evolucionar sin preocuparnos si un cambio que introdujimos dañó el código anterior.

Tipos de Pruebas

En este post nos concentraremos en dos tipos de prueba principalmente

  • Pruebas Unitarias Se prueban funcionalidades muy específicas del código, por ejemplo, un solo método de una clase; cualquier componente externo, distinto a la clase actual se debe simular, para evitar que este afecte la prueba.

  • Pruebas de Integración Estas garantinzan que un conjunto de componentes interactúen de manera adecuada. Por ejemplo en Spring se podría probar un endpoint y sus respectivos servicios y repositorios.

Implementando Pruebas en nuestro código

Vamos a generar nuestro proyecto usando la página https://start.spring.io/, solamente agregando soporte web, y dando clic en el botón de generar proyecto.

Una vez hayas generado el proyecto y lo hayas importado en tu IDE de preferencia, el primer paso es crear un componente que llamaremos GreetingService, cuyo único objetivo es retornar la cadena “Hola Mundo”.

import org.springframework.stereotype.Component;

@ComponentpublicclassGreetingService{

    public String helloWorld(){
        return"Hola Mundo";
    }

}

El segundo paso es crear un controlador, que inyecte este servicio y retorne el valor del método helloWorld con un código de status 200.

@ControllerpublicclassGreetingController{ 

    privatefinal GreetingService greetingService;

    @AutowiredpublicGreetingController(GreetingService greetingService){
        this.greetingService = greetingService;
    }

    @GetMapping("/hello")
    public ResponseEntity sayHello(){
        return ResponseEntity.ok(greetingService.helloWorld());
    }
}

Pruebas Unitarias

Lo primero que probaremos será la clase GreetingService, esta no tiene ninguna dependencia por lo que es la más simple de probar. Lo primero a tener en cuenta es la anotación @Test, esta se debe poner en todos los métodos que ejecuten pruebas. También es importante resaltar el método Assert.assertEquals, que verifica que dos parámetros sean iguales, en este caso se verifica que esté retornando la cadena hola mundo. Junit provee métodos similares a este, para ver una lista más exhaustiva pueden entrar a JUnit Api.

import org.junit.Assert;import org.junit.Test;publicclassGreetingServiceUnitTest{

    private GreetingService greetingService = new GreetingService();

    @Test
    publicvoid itShouldSayHolaMundo() {
        Assert.assertEquals("Hola Mundo", greetingService.helloWorld());
    }

}

Ahora probaremos el controlador, este es un poco más dificil de probar ya que tiene la dependencia con GreetingService, para ayudarnos con esto simularemos el GreetingService usando Mockito para evitar que esta clase afecte la prueba del controlador.

De este código es importante resaltar los métodos Mockito.mock y Mockito.when, los cuales permiten crear un objeto simulado y cambiar su comportamiento, en este caso hacemos que el GreetingService retorne Saludos en lugar de Hola Mundo (solo por razones demostrativas). La anotación @Before se usa en los métodos que inicializan los objetos antes de una prueba.

NOTA: También se podría usar la anotación @WebMvc para esta prueba, pero de esta manera se entiende mejor cómo funciona Junit junto a Mockito.

import com.davidfcalle.platzitesting.controller.GreetingController;import com.davidfcalle.platzitesting.service.GreetingService;import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.mockito.Mock;import org.mockito.Mockito;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;

public class GreetingControllerUnitTest {

    private GreetingController controller;
    private GreetingService greetingService;

    @Before
    public void setUp() {
        greetingService = Mockito.mock(GreetingService.class);
        controller = new GreetingController(greetingService);
    }

    @Test
    public void itShouldReturnTheServiceValueWith200StatusCode() {
        Mockito.when(greetingService.helloWorld()).thenReturn("Saludos");
        ResponseEntity<String> httpResponse = controller.sayHello();

        Assert.assertEquals(httpResponse.getStatusCode(), HttpStatus.OK);
        Assert.assertEquals("Saludos", httpResponse.getBody());
    }

}

Pruebas de Integración

Por último haremos una prueba tenga en cuenta ambos componentes al tiempo. Para esto usaremos MockMvc que es un utilitario de Spring para pruebas de integración.

De esta clase es importante resaltar la anotación @SpringBootTest, en la cual especificamos nuestra clase main para cargar el contexto de Spring. En el setup de la prueba se puede ver que inicializamos MockMvc para después usarlo llamando al endpoint especificado y hacer una prueba sobre el código de status y el contenido del resultado.

Esta prueba fue diferente a la anterior ya que en esta se prueba que toda la aplicación esté bien y la interacción de sus componentes funcione como deseamos.

import org.junit.*;import org.junit.runner.*;import org.springframework.beans.factory.annotation.*;import org.springframework.boot.test.autoconfigure.web.servlet.*;import org.springframework.boot.test.mock.mockito.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.MockMvcBuilder;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import org.springframework.web.context.WebApplicationContext;import static org.assertj.core.api.Assertions.*;import static org.mockito.BDDMockito.*;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@SpringBootTest(
        classes = PlatziTestingApplication.class
)
public class PlatziTestingApplicationTests {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

	@Test
	public void testHelloEndpointIsOK() throws Exception {
        this.mockMvc.perform(get("/hello"))
            .andExpect(status().isOk())
            .andExpect(content().string("Hola Mundo"));
	}

}

<h1>Conclusión</h1>

Siguiendo este tutorial tuviste una introducción práctica a testear aplicaciones de Spring, ahora podrás agregarle pruebas a tus aplicaciones para estar más tranquilo al momento de evolucionar tu sistema.

Escribe tu comentario
+ 2
Ordenar por:
2
5753Puntos

Excelente aporte David.

Fue muy claro el sentido y el valor que tiene el hecho de realizar las pruebas de nuestros fuentes.

1
19583Puntos

Lo que estoy viendo en tu ejemplo es que no puedo mezclar un ejemplo de spring con Mockito y spring boot con MockMvc. Hubiese sido bueno que dejaras el código de los dos ejemplos para visualizar la configuración de cada uno, ya que en el segundo me sale lo siguiente: IllegalStateException: Could not load CacheAwareContextLoaderDelegate.

Acá dejo el código del primero ejemplo, que involucra sólo las pruebas unitarias: https://github.com/cesardramirez/spring-junit-mockito

1
8703Puntos
un año

Hola Cesar,

revisé, el problema es que mezclas las versiones 2 y 4 de spring en el pom, desafortunadmente no subí el codigo que hice a github. Sin embargo, me tomé la libertad de mandar un PR en github par ayudarte a solucionar el problema y para que los demás lo usen como referencia.

Acá el PR: https://github.com/cesardramirez/spring-junit-mockito/pull/1

Para los que también les pasa esto, si generan el proyecto usando a https://start.spring.io/, no deberían tener este problema ya que crea el pom por nosotros con las dependencias correctas.

1

Hace poco terminé el curso Profesional de Java EE, he desarrollado una api rest propia con todo lo aprendido.
Ahora estoy intentando añadirle pruebas unitarias y de integración a mi aplicación spring boot, tengo una grandísima duda, y es muy posible que sea una tontería, ya tengo bastante claro como se programan los test (gracias a este tutorial) lo que no sé es cómo se ejecutan esos test?.

1
19583Puntos
un año

Depende del IDE que estés manejando. Por ejemplo, en ItelliJ lo que tienes que hacer es dar clic derecho en el método o clase y dar clic en Run.

2
19583Puntos
un año

También se me olvidó decirte. Cuando tu ejecutas el comando mvn install o mvn test, en la terminal ya estarías visualizando el resultado de cada una de las pruebas.