Testes Unitários de API REST: Configuração Standalone
Ao concluirmos esta aula, nós:
- Saberemos como declarar e obter as dependências necessárias para testar APIs REST com Maven e Gradle 9 (Kotlin DSL).
- Seremos capazes de identificar a configuração mínima necessária quando escrevemos testes unitários para uma API REST em modo standalone.
- Compreenderemos como configurar o sistema sob teste (SUT) para utilizar nosso próprio
ObjectMappercustomizado (comKotlinModulee suporte ajava.time).
Obtendo as Dependências Necessárias
Quando queremos escrever testes unitários para uma API REST que consome e produz documentos JSON usando o Spring MVC Test framework, precisamos adicionar as seguintes dependências na nossa configuração de build:
- Jackson Databind e Jackson Module Kotlin (
com.fasterxml.jackson.core:jackson-databindecom.fasterxml.jackson.module:jackson-module-kotlin): O Spring MVC utiliza o Jackson para serializar objetos de retorno em documentos JSON e desserializar o corpo das requisições HTTP (@RequestBody) em data classes Kotlin. - Jayway JsonPath (
com.jayway.jsonpath:json-path): O Spring MVC Test framework utiliza o JsonPath por baixo dos panos quando escrevemos asserções para a estrutura e os valores de documentos JSON retornados usandojsonPath(...). - JUnit Jupiter 6 (
org.junit.jupiter:junit-jupiter): Nosso framework de execução de testes. - MockK (
io.mockk:mockk): Nossa biblioteca idiomática em Kotlin para substituir os serviços chamados pelo@RestControllerpor dublês de teste (stubs e mocks). - Spring Test e Spring Web MVC (
org.springframework:spring-testeorg.springframework:spring-webmvc, ou simplesmenteorg.springframework.boot:spring-boot-starter-testeorg.springframework.boot:spring-boot-starter-web). - Jakarta Servlet API (
jakarta.servlet:jakarta.servlet-api): Necessária para compilar e executar oMockHttpServletRequesteMockHttpServletResponseem memória.
Dica Prática com Spring Boot 4.1: Ao adicionar
testImplementation("org.springframework.boot:spring-boot-starter-test")eimplementation("org.springframework.boot:spring-boot-starter-web")no seubuild.gradle.kts, todas as dependências acima (exceto o MockK, que adicionamos explicitamente) já são incluídas e gerenciadas automaticamente na versão compatível!
Caso você esteja configurando um projeto com gerenciamento manual de dependências no Maven (pom.xml), as dependências necessárias são:
|
|
Se estivermos usando o Gradle 9 (Kotlin DSL — build.gradle.kts), nossa configuração fica assim:
|
|
Vamos agora descobrir como configurar o sistema sob teste no modo standalone!
Configurando o Sistema Sob Teste (SUT)
A configuração standalone que devemos usar ao escrever testes unitários para uma API REST depende da complexidade da nossa aplicação e de como serializamos objetos para JSON. Vamos examinar dois cenários comuns:
- Nossa aplicação utiliza a configuração padrão do Spring MVC (não customiza o
ObjectMappernem osHttpMessageConverters). - Nossa aplicação utiliza um
ObjectMappercustomizado.
Caso 1: Usando a Configuração Padrão
Se a nossa API REST apenas retorna objetos simples (ou data classes) e não exige configurações especiais de serialização no ObjectMapper, precisamos apenas instanciar o controlador @RestController passando seus dublês de teste (mockk()) via construtor e construir o MockMvc com MockMvcBuilders.standaloneSetup(...).
Suponha que estejamos testando a classe TaskCrudController:
|
|
A configuração mínima da nossa classe de teste (TaskCrudControllerTest) é extraordinariamente simples:
|
|
Quando o MockMvcBuilders.standaloneSetup(...) é executado e detecta o Jackson no classpath, ele registra automaticamente uma instância padrão de MappingJackson2HttpMessageConverter.
Contudo, em aplicações reais com Spring Boot e Kotlin, é muito comum customizarmos o ObjectMapper (por exemplo, para formatar datas java.time.Instant / ZonedDateTime em ISO-8601 em vez de timestamps numéricos, ignorar campos nulos ou registrar o KotlinModule). Como garantimos que o teste unitário standalone use exatamente o mesmo ObjectMapper da produção?
Caso 2: Usando um ObjectMapper Customizado
Suponha que nossa aplicação possua um método factory (ou @Bean) que configura um ObjectMapper customizado:
- Ele desabilita a feature
SerializationFeature.WRITE_DATES_AS_TIMESTAMPSpara que datas e horas sejam escritas como strings no padrão ISO-8601 (ex:"2026-11-01T12:00:00Z"). - Ele registra o
JavaTimeModule(para dar suporte à API de data e hora do Java 8+) e oKotlinModule(para suporte completo a construtores primários dedata classes Kotlin).
Podemos criar uma função factory estática na nossa classe WebTestConfig que instancia esse ObjectMapper e o envolve em um MappingJackson2HttpMessageConverter:
|
|
Agora, no método @BeforeEach da nossa classe de teste (TaskCrudControllerTest), podemos instruir o StandaloneMockMvcBuilder a usar o nosso MappingJackson2HttpMessageConverter customizado chamando o método .setMessageConverters(...):
|
|
Atenção ao usar
.setMessageConverters(...): Quando invocamos.setMessageConverters(...)noStandaloneMockMvcBuilder, ele substitui a lista padrão de conversores HTTP pelos conversores que você passar. Na grande maioria das APIs REST JSON, oMappingJackson2HttpMessageConverteré tudo o que você precisa!
Resumo
Esta aula nos ensinou três coisas fundamentais:
- O Spring MVC Test framework utiliza o Jayway JsonPath (
com.jayway.jsonpath:json-path) quando escrevemos asserções sobre documentos JSON retornados pela API. - Na maioria dos casos simples, não precisamos adicionar nenhuma configuração extra ao
StandaloneMockMvcBuilderalém de passar o controlador REST sob teste paraMockMvcBuilders.standaloneSetup(...). - Se a nossa aplicação utiliza um
ObjectMappercustomizado (como formatação ISO-8601 para datasjava.timeeKotlinModule), devemos criar umMappingJackson2HttpMessageConverterque utilize esseObjectMappere registrá-lo com.setMessageConverters(...)ao construir oMockMvc.