Testing en Spring Boot
Para realizar testing en Spring Boot podemos utilizar multiples tecnologias. Hoy en dia y de forma moderna se utilizan:
- JUnit 5 (Jupyter). Para marcar metodos de testing
- AspectJ Assertions. Para realizar las aserciones
- notes/TestContainers. Para instanciar bases de datos
- Java Faker. Para generar datos
Para realizar los tests podemos seguir la metodologia de *Given, When, Then.
# Testing a Data Acess Layer (Repositorios, JPA, JDBC, BD).
Para realizar testing a la capa de acceso a datos, podemos utilizar la tecnologia de notes/TestContainers para instanciar a nuestras bases de datos y conectarnos a ella solo durante el testing. Algo importante a considerar esque, al realizar test unitarios a esta capa debemos evitar a toda costa utilizar notes/Anotacion SpringBootTest.
# Testing a Spring Data JDBC
Para testear a Spring Data JDBC tenemos que aprovechar de algo como Flyway (o un script para instanciar las tablas) que nos permita hacerlo cada que realizamos los test dentro de nuestro notes/TestContainers.
Con Flyway podriamos ejecutar nuestras migraciones de forma programatica usando:
| |
De esta forma, podriamos pasar a realizar nuestros Test de la capa de datos utilizando JUnit 5.
| |
# Testing a Spring Data JPA
Para testear de forma unitaria Spring Data JPA, lo que debemos hacer es testear todos los repositorios que extiendan de cualquiera de las interfaces que nos provee JPA. En dichos repositorios lo unico que debemos testar son los metodos extra que le agregamos a dicho repositorio de forma personalizada (Ya sea utilizando el dialecto de Spring Data o utilizando JPQL).
Suponiendo que tenemos el siguiente repositorio:
| |
Los unicos metodos que debemos testear son existsCustomerByEmail(String email) y boolean existsCustomerById(Long customerId).
Lo que debemos hacer es aprovechar la anotacion @DataJpaTest para tener acceso al repositorio y desactivar que los tests se ejecuten con una base de datos embebida (H2). Para hacer esto ultimo utilizamos la anotacion @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE). Tras desactivarlo, este se intentara conectar a la base de datos que tengamos configurado en el application.properties. En caso de hacer una configuracion correcta de Testcontainers, no deberiamos tener mucho problema para que este se conecte a ellos.
| |
Posterior a ello, ya podemos realizar todos los tests necesarios.
# Testing a Spring Data JPA usando mocks.
En caso de tener una clase la cual utilice dentro de ella un repositorio para ofrecer los servicios. Podemos utilizar mocks para Mockear los repositorios y que podamos testear cada metodo de forma independiente. Para ello, se utiliza la libreria de Mockito. Podemos utilizar el setup y el teardown para inicializar un nuevo mock por cada test, lo que nos quedaria de la siguiente forma:
| |
# Testing al Business Layer (Servicios, Mappers).
Para testear el business layer, basicamente lo que ocupamos hacer es aprovecharnos mucho del uso de los Mocks. Especialmente, los metodos que seran utiles son:
- when(). Sirven para darle un comportamiento al mock cuando un metodo es invocado
- verify(X, never()). Sirve para marcar que un metodo nunca deberia ser invocado, en caso de encontrar un problema en medio
- verify(X). Sirve para marcar que un metodo debio de haber sido invocado
- ArgumentCaptors. Sirve para atrapar en medio de la ejecucion un objeto que es enviado por parametro al mock, usualmente este argumento luego es comparado usando aserciones.
# Testing al API Layer (Test de Integracion, controladores).
Para realizar los tests de integracion, basicamente lo que necesitamos es probar la capa de los Controller.
El primer paso es tener en cuenta que debemos inicializar todo el contesto de Spring, por tanto, la notes/Anotacion SpringBootTest sera utilizada junto con un atributo para inicializar el servidor embebido notes/Apache Tomcat.
Para realizar esto, ocupamos un cliente HTTP que permita hacer peticiones de forma programatica. En Spring, contamos con el WebTestClient que nos permite hacer comprobaciones, solicitudes, enviar peticiones con cuerpo y todas las funcionalidades que tiene un cliente HTTP.