Especificando Controladores Spring MVC com Kotest: Configuração
Depois de concluirmos esta aula, compreenderemos como configurar o Spring MVC Test Framework (MockMvc em modo standalone) quando estivermos escrevendo testes unitários com o Kotest Framework 6 e MockK.
1. Configurando o Sistema Sob Especificação
Quando escrevemos testes unitários para controladores Spring MVC usando o Kotest, configuramos o sistema sob especificação criando uma instância de MockMvc que será utilizada pelos blocos de teste da nossa especificação.
Para garantir que nossos testes unitários sejam ultrarrápidos (executando em poucos milissegundos sem subir o ApplicationContext do Spring) e 100% isolados entre si, seguimos três passos:
- Identificamos as dependências exigidas pelo construtor do controlador testado.
- Criamos os dublês de teste necessários (
mockk<TaskCrudService>()) e os armazenamos em propriedades isoladas por caso de teste (comIsolationMode.InstancePerLeafou resetando-os nobeforeEach). Isso garante que cada caso de teste receba seus próprios dublês limpos e que a configuração feita em um teste nunca afete os demais. - Criamos uma instância de
MockMvcusando a configuração standalone (MockMvcBuilders.standaloneSetup(...)) e a armazenamos em uma propriedade isolada da especificação. Assim, cada caso de teste interage com seu próprio controlador conectado a dublês limpos.
Vamos ver como aplicar esses três passos primeiro para um controlador web tradicional (@Controller) e depois para um controlador de API REST (@RestController).
2. Configurando Testes Unitários para um Controlador Web Tradicional (@Controller)
Suponha que estejamos escrevendo especificações unitárias para a classe TaskCrudController (versão web tradicional baseada em views):
|
|
Como podemos ver, esse controlador possui duas dependências no construtor:
TaskCrudService: fornece as operações de CRUD para tarefas.MessageSource: usado para buscar mensagens internacionalizadas (como mensagens flash de feedback exibidas ao usuário após criar ou excluir uma tarefa).
Depois de identificarmos as dependências do controlador, configuramos o sistema sob especificação na nossa classe TaskCrudControllerSpec seguindo três passos:
- Criamos um novo objeto
StaticMessageSourcee o armazenamos em uma propriedade isolada. UsamosStaticMessageSourcedo próprio Spring porque ele é um fake em memória que nos permite registrar mensagens programaticamente (messageSource.addMessage(...)), o que é muito mais limpo do que fazer stubbing de métodos doMessageSource. - Criamos um mock para
TaskCrudServicecommockk<TaskCrudService>(). - Criamos o objeto
MockMvcusandoMockMvcBuilders.standaloneSetup(...)auxiliado pelos métodos factory da nossa classe Object MotherWebTestConfig(exceptionResolver(),fixedLocaleResolver()ejspViewResolver()):
|
|
[!NOTE] A classe utilitária
WebTestConfigé exatamente a mesma que construímos no Tópico 07 do Capítulo 01 (Pacote Iniciante), fornecendo os métodos estáticosexceptionResolver(),fixedLocaleResolver(),jspViewResolver()eobjectMapperHttpMessageConverter()para evitar duplicação na configuração doMockMvcBuilders.standaloneSetup(...).
Vamos ver agora como configurar o sistema sob especificação quando estamos testando uma API REST!
3. Configurando Testes Unitários para uma API REST (@RestController)
Agora suponha que estejamos escrevendo especificações unitárias para a versão REST de TaskCrudController, que processa requisições enviadas para /api/task:
|
|
Como podemos ver, este controlador possui apenas uma dependência: TaskCrudService.
Para configurar o sistema sob especificação na nossa classe TaskCrudRestControllerSpec, seguimos dois passos:
- Criamos um mock para
TaskCrudServiceusandomockk<TaskCrudService>()em uma propriedade isolada. - Criamos o objeto
MockMvcusandoMockMvcBuilders.standaloneSetup(...), registrando o@ControllerAdvicede tratamento de erros (TaskErrorHandler()), ofixedLocaleResolver()e o conversor HTTP JSON do Jackson (objectMapperHttpMessageConverter()):
|
|
Resumo
Nesta aula, aprendemos dois princípios fundamentais para configurar testes unitários de controladores Spring MVC no Kotest:
- Devemos armazenar as dependências do controlador testado (
service,messageSource) em propriedades isoladas por caso de teste (IsolationMode.InstancePerLeaf) para garantir que o stubbing ou as interações de um cenário nunca afetem outros cenários. - Devemos instanciar o
MockMvcviaMockMvcBuilders.standaloneSetup(...)também em uma propriedade isolada por teste, garantindo que cada cenário execute contra um controlador limpo e sem custo de inicialização do contexto Spring.