Devops Integrated Tests - QuantumBitBR/API_5SEM GitHub Wiki
O teste de integração é um nível de teste de software que verifica a interação entre diferentes módulos, componentes ou sistemas para garantir que eles funcionem corretamente quando combinados.
Ele ocorre após os testes unitários (que avaliam partes individuais do código) e antes dos testes de sistema (que verificam o software como um todo).
Para o bom desenvolvimento voltado para para testes de Integração, devemos destacar uma pessoa do time para atuar como QA, pois ele será o responsável por desenvolver a dinâmica dos testes. Este documento descreve as atividades do profissional de QA (Quality Assurance) ao longo de uma sprint em equipes ágeis, com foco em integração contínua de qualidade no desenvolvimento.
- Entende as histórias do backlog priorizadas.
- Ajuda a definir critérios de aceitação claros com o Product Owner (PO).
- Estima o esforço de testes em conjunto com os desenvolvedores.
- Cria casos de teste com base nas histórias e nos critérios de aceitação.
- Inicia a elaboração de testes manuais e automatizados antes mesmo da implementação.
- Testa os incrementos à medida que são entregues (teste contínuo).
- Participa de testes de integração e testes de API, se necessário.
- Fornece feedback rápido — quanto mais cedo os problemas forem detectados, melhor.
- Integra testes automatizados ao pipeline de CI/CD.
- Automatiza testes funcionais .
- Reporta bugs encontrados, dúvidas sobre critérios, dependências e impedimentos.
- Alinha com os desenvolvedores sobre funcionalidades prontas para teste.
- Valida os critérios de aceitação.
- Confirma se a Definition of Done (DoD) foi atendida.
- Pode demonstrar funcionalidades testadas.
- Aponta possíveis limitações ou áreas que requerem atenção futura.
- Colabora para melhorar o processo de testes e integração com o time.
- Apresenta sugestões sobre qualidade, automação, ambiente e comunicação.
- Confiança nas alterações de código.
- Documentação viva da lógica implementada.
- Detecção precoce de erros e regressões.
- Facilidade para refatorações seguras.
- Redução de falhas em produção.
- JUnit 5 (
@Test
, integração com Spring) - Spring Boot Test (carregamento do contexto completo da aplicação)
- WebTestClient (para chamadas HTTP reativas)
- AssertJ (para assertions fluentes)
- Spring SQL Support (
@Sql
para scripts de inserção e limpeza) - Testcontainers (PostgreSQL) (banco de dados isolado e real para testes de integração)
<dependencies>
<!-- Starter de testes do Spring Boot (JUnit, AssertJ, Mockito etc.) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- WebFlux (necessário para o WebTestClient) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
<!-- Testcontainers: PostgreSQL + JUnit 5 -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
</dependencies>
package com.quantum.stratify.integracao;
import com.quantum.stratify.web.dtos.PercentualStatusUsuarioDTO;
import com.quantum.stratify.web.dtos.TotalCardsDTO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@Testcontainers
@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Sql(scripts = {
"classpath:sql/userStories/delete.sql",
"classpath:sql/userStories/insert.sql"
}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "classpath:sql/userStories/delete.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
class UserStoryIT {
@Container
static PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
registry.add("spring.datasource.username", postgresContainer::getUsername);
registry.add("spring.datasource.password", postgresContainer::getPassword);
registry.add("spring.datasource.driver-class-name", postgresContainer::getDriverClassName);
registry.add("spring.liquibase.enabled", () -> true);
registry.add("spring.liquibase.change-log", () -> "classpath:db/changelog/changelog-master.xml");
}
@Autowired
WebTestClient testClient;
@Test
void deveRetornarTotalCards_status200() {
TotalCardsDTO responseBody = testClient.get()
.uri("/userStory/total-cards")
.exchange()
.expectStatus().isOk()
.expectBody(TotalCardsDTO.class)
.returnResult()
.getResponseBody();
assertThat(responseBody).isNotNull();
if (responseBody != null) {
assertThat(responseBody.quantidadeUserStories()).isEqualTo(1);
}
}
@Test
void deveRetornarPercentualPorStatus_status200() {
List<PercentualStatusUsuarioDTO> responseBody = testClient.get()
.uri("/userStory/percentual-por-status")
.exchange()
.expectStatus().isOk()
.expectBodyList(PercentualStatusUsuarioDTO.class)
.returnResult()
.getResponseBody();
assertThat(responseBody).isNotNull();
assertThat(responseBody).hasSize(1);
}
}
-
@SpringBootTest
: carrega o contexto completo da aplicação. -
webEnvironment = RANDOM_PORT
: evita conflito de portas entre testes paralelos. -
@Testcontainers
e@Container
: inicializa PostgreSQL real isolado. -
@Sql
: prepara o estado do banco (inserção e limpeza de dados).
@Sql(scripts = {"cleanup.sql", "insert.sql"}, executionPhase = BEFORE_TEST_METHOD)
@Sql(scripts = "cleanup.sql", executionPhase = AFTER_TEST_METHOD)
- Use nomes de métodos de teste descritivos e padronizados:
- Em português:
deveRetornarTempoMedioDoProjeto()
- Ou em inglês:
shouldReturnAverageTimePerProject()
- Em português:
- Deixe os testes independentes entre si.