Testes de Integração de API REST: Configuração
Ao concluirmos esta aula, entenderemos como podemos eliminar código de configuração duplicado quando configuramos nossos testes de integração para uma API REST.
[!NOTE] Esta aula assume que:
- Você sabe configurar o sistema sob teste ao escrever testes de integração (consulte o tópico sobre Configuração de Testes de Integração).
- Você sabe criar uma classe request builder que envia requisições HTTP para o sistema sob teste (consulte a aula Testes Unitários de API REST com Kotlin e JUnit 5: Configuração).
- Você sabe configurar o sistema sob teste ao escrever testes de integração para um repositório Spring com Kotlin e JUnit Jupiter (consulte a aula Testes de Integração de Repositório: Configuração).
Obtenha o código-fonte no GitHub
Configurando Nossos Testes de Integração
Podemos configurar nossos testes de integração seguindo estes passos:
Primeiro, como queremos eliminar código de configuração duplicado dos nossos testes de integração, precisamos criar uma anotação customizada (meta-anotação composta) que contenha a configuração compartilhada por todos os nossos testes de integração de API REST. Podemos criar essa anotação seguindo estes passos:
- Criar uma nova classe de anotação (
annotation class WebIntegrationTest). - Garantir que nossa anotação customizada possa ser aplicada a uma classe de teste (
@Target(AnnotationTarget.CLASS)). - Garantir que nossa anotação customizada seja armazenada na saída binária (bytecode compilado) e fique visível para reflexão em tempo de execução (
@Retention(AnnotationRetention.RUNTIME)). - Garantir que nossa anotação customizada seja incluída na documentação gerada a partir das nossas classes de teste (
@MustBeDocumented). - Habilitar a autoconfiguração do framework Spring MVC Test (
@AutoConfigureMockMvc). Quando habilitamos essa funcionalidade no Spring Boot 4.1.2, o framework Spring TestContext cria e autoconfigura uma instância pronta deMockMvc(totalmente compatível com a MockMvc Kotlin DSL), que pode ser injetada diretamente em nossas classes de teste. - Garantir que nossa anotação customizada utilize a configuração que criamos anteriormente quando escrevemos testes de integração para um repositório Spring (
@DatabaseIntegrationTest).
Depois de criarmos a anotação @WebIntegrationTest, seu código-fonte fica da seguinte forma:
|
|
[!TIP] Composição de Meta-Anotações no Spring Boot:
Observe como a anotação
@WebIntegrationTestherda toda a infraestrutura definida em@DatabaseIntegrationTest:
@SpringBootTest: Carrega o contexto completo da aplicação Spring Boot (ApplicationContext).@ActiveProfiles("integrationTest"): Ativa o perfil que direciona a aplicação para a URL dinâmica do Testcontainers PostgreSQL (jdbc:tc:postgresql:17-alpine:///integrationTest).@Tag("integrationTest"): Permite filtrar a execução de testes de integração via Gradle ou pipelines de CI/CD.@AutoConfigureMockMvc: Adiciona o suporte ao mock do ambiente web do Spring MVC, permitindo disparar requisições HTTP simuladas de ponta a ponta sem a necessidade de subir um servidor de aplicação em uma porta TCP real.
No arquivo de build do projeto (build.gradle.kts), as dependências necessárias para suportar essa infraestrutura de testes de integração com a stack moderna (Gradle 9.8.2 Kotlin DSL, Spring Boot 4.1.2, Kotlin 2.4.21, JUnit Jupiter 6.0.3, AssertJ 3.27.7 e Testcontainers 2.0.5) são declaradas conforme o exemplo abaixo:
|
|
Segundo, quando criamos uma nova classe de teste que contenha testes de integração para uma API REST, devemos seguir estes passos:
- Anotar a classe de teste com a anotação
@WebIntegrationTest. - Criar uma propriedade privada somente leitura (
private val) que contenha um objetoMockMvce injetar o valor dessa propriedade utilizando injeção via construtor (@Autowired private val mockMvc: MockMvc). Nosso objeto request builder utilizará essa propriedade quando enviar requisições HTTP ao sistema sob teste. - Criar um novo objeto request builder (
TaskCrudRequestBuilder) e armazenar esse objeto em uma propriedade privada somente leitura (private val requestBuilder = TaskCrudRequestBuilder(mockMvc)). Nossas funções de teste utilizarão essa propriedade quando enviarem requisições HTTP ao sistema sob teste.
Depois de configurarmos o sistema sob teste, o código-fonte da nossa classe de teste fica da seguinte forma:
|
|
[!NOTE] Injeção de Dependências via Construtor no JUnit Jupiter com Kotlin:
Ao contrário do JUnit 4 (que exigia anotações
@Autowiredem campos públicos ou variáveis mutáveis comlateinit var), o JUnit Jupiter (JUnit 5 e JUnit 6) suporta resolução de parâmetros via construtor por meio doSpringExtension.No Kotlin, declarar
@Autowired private val mockMvc: MockMvcno construtor primário da classe de teste garante:
- Imutabilidade real: A propriedade é uma referência imutável (
val), prevenindo reatribuições acidentais.- Inicialização segura: O objeto
MockMvcé injetado pelo Spring antes da instanciação de qualquer propriedade dependente, permitindo queprivate val requestBuilder = TaskCrudRequestBuilder(mockMvc)seja inicializado imediatamente no corpo da classe, sem risco deUninitializedPropertyAccessException.
O Padrão Request Builder com MockMvc
A classe TaskCrudRequestBuilder atua como um wrapper especializado sobre a instância de MockMvc. Ela encapsula a complexidade da montagem das requisições HTTP (caminhos de endpoint, cabeçalhos Content-Type, conversão de payloads JSON e execução com o MockMvc ou com a MockMvc Kotlin DSL).
Veja um exemplo de como a classe TaskCrudRequestBuilder pode ser estruturada:
|
|
Dessa forma, as funções de teste tornam-se extremamente legíveis, focadas no comportamento do negócio e desacopladas dos detalhes técnicos de baixo nível das chamadas HTTP.
Agora podemos configurar nossos testes de integração sem escrever nenhum código de configuração duplicado. Vamos resumir o que aprendemos nesta aula.
Resumo
Esta aula nos ensinou uma lição essencial:
- Como queremos configurar nossos testes de integração sem escrever código de configuração duplicado em cada classe de teste, devemos criar uma anotação customizada (
@WebIntegrationTest) que contenha a configuração compartilhada pelos nossos testes de integração de API REST (combinando@AutoConfigureMockMvccom@DatabaseIntegrationTest).