🌱 Digital Garden

Search

Search IconIcon to open search

Testing en Spring Boot

Last updated Aug 6, 2023 Edit Source

Para realizar testing en Spring Boot podemos utilizar multiples tecnologias. Hoy en dia y de forma moderna se utilizan:

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:

1
2
3
4
5
6
Flyway flyway = new Flyway(
	url,
	username,
	password
);
flyway.migrate();

De esta forma, podriamos pasar a realizar nuestros Test de la capa de datos utilizando JUnit 5.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Test  
void selectCustomerById() {  
    // Given  
    Customer customer = ENTITY_FAKER.getCustomer();  
    underTest.insertCustomer(customer);  
    Long id = this.getCustomerIdInDatabase(customer);  
      
    // When  
    Optional<Customer> actualOptional = underTest.selectCustomerById(id);  
  
    // Then  
    assertThat(actualOptional).isPresent().hasValueSatisfying(actual -> {  
        assertThat(actual.getId()).isEqualTo(id);  
        assertThat(actual.getEmail()).isEqualTo(customer.getEmail());  
        assertThat(actual.getName()).isEqualTo(customer.getName());  
        assertThat(actual.getAge()).isEqualTo(customer.getAge());  
    });  
}  
  
@Test  
void givenSavedCustomerIdThenCustomerExistenceIsTrue() {  
    // Given  
    Customer saved = ENTITY_FAKER.getCustomer();  
    underTest.insertCustomer(saved);  
    Long savedId = this.getCustomerIdInDatabase(saved);  
  
    // When  
    boolean exists = underTest.existsCustomerById(savedId);  
      
    // Then  
    assertThat(exists).isTrue();  
}

# 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:

1
2
3
4
5
public interface CustomerRepository extends JpaRepository<Customer, Long> {  

    boolean existsCustomerByEmail(String email);  
    boolean existsCustomerById(Long customerId);  
}

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.

1
2
3
4
5
6
7
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CustomerRepositoryTest extends AbstractTestcontainers {

	@Autowired
	private CustomerRepository underTest;
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class CustomerJPADataAccessServiceTest {  
    private CustomerJPADataAccessService underTest;  
    @Mock   
	private CustomerRepository customerRepository;  
    private AutoCloseable autoCloseable;  
      
    @BeforeEach  
    void setUp() {  
        this.autoCloseable = MockitoAnnotations.openMocks(this);  
        underTest = new CustomerJPADataAccessService(customerRepository);  
    }
    
	@AfterEach  
	void tearDown() throws Exception {  
	    this.autoCloseable.close();  
	}

# 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:

# 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.