Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

...

Vamos a ver cómo realizar tests unitarios (con jUnit) en nuestros proyectos Spring Boot, con ejemplos de algunas acciones básicas.

Importante: Las clases encargadas de lanzar los test deben crearse dentro de los paquetes src/test/java/ y no con los del código fuente.

Clases de tests

Las clases en las que situemos nuestros tests tendrás que ir precedidas de la anotación @SpringBootTest:

...

Bloque de código
languagejava
@Test
void getExpedienteTest() {

}

Properties para el test

Se pueden definir propiedades específicas para los tests. Para ello, crearemos un archivo application-test.properties y lo colocaremos en src/main/resources. Después, para que los tests utilicen las properties de ese archivo, habrá que añadir la siguiente anotación a las clases de los tests:

Bloque de código
languagejava
@TestPropertySource( locations = "classpath:application-test.properties" )

De este modo se cogerán las properties que estén presentes en este archivo, pero si no están en este pero sí en el application.properties normal, se cogerán las del application.properties.

Info
titleOjo

No se deben subir claves a GitLab, por lo que dejaremos en blanco las properties de usuario y password de la base de datos (el test debe mockear servicios externos, por lo que no se debe llamar a base de datos). Además, debemos poner la property spring.jpa.hibernate.ddl-auto con el valor none, para que no se compruebe la conexión a base de datos cuando arranque la aplicación para hacer un test.


En gitlab no se están subiendo los ficheros application.properties, por lo que si tenemos test que necesiten alguna configuración de este fichero deberemos crear una variable de tipo File llamada PROPIEDADES_TEST y en Value copiar y pegar el contenido del fichero que necesitamos

Image Added



Before: ejecutar código antes de los tests

...

@SpyBean - Spy de un bean a nivel global

Por último, podemos añadir la anotación @SpyBean las propiedades de la clase, que creará el spy a nivel global, de contexto. Esto quiere decir que todas las instancias de ese bean serán ese spy, en lugar de únicamente el objeto que definimos en la clase de los tests. Esto se aplicará a todos los tests que tengamos en la clase.

Bloque de código
languagejava
@SpyBean
UserRepository mockRepository;

...

Bloque de código
languagejava
Mockito.doReturn( "asdf" ).when( expedientesService ).getExpediente( nullable( String.class ) );

En el caso de que no queramos devolver nada, que sea un método void, en lugar de usar doReturn(...) utilizaremos doNothing().

Testear métodos @Transactional

Cuando se llama a un método @Transactional, se intentará abrir una conexión con base de datos al llamarlo, por lo que nos dará error directamente aunque hayamos mockeado las operaciones que se hagan dentro de dicho método. Para evitar esto, debemos añadir dos clases de configuración para gestionar las transacciones en los tests. Bajo una carpeta config, añadiremos estas dos clases:

Bloque de código
languagejava
titleNoOpTransactionManager.java
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;

public class NoOpTransactionManager extends AbstractPlatformTransactionManager {

    @Override
    protected Object doGetTransaction() throws TransactionException {
        return new Object();
    }

    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
    }

    @Override
    protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
    }

    @Override
    protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
    }
}


Bloque de código
languagejava
titleTestConfig.java
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@TestConfiguration
@EnableTransactionManagement
public class TestConfig {

    @Bean
    public PlatformTransactionManager transactionManager() {
        // Return a mock transaction manager or a do-nothing implementation
        return new NoOpTransactionManager();
    }
}

Por último, en la clase de Test en la que se pruebe el método @Transactional, añadimos la anotación @Import(TestConfig.class):

Bloque de código
languagejava
titleClase del test correspondiente
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
@Import(TestConfig.class)
class TestSolicitudes {
    ...
    ...
    ...
}

Simular peticiones a servicio REST

...