Usando WireMock para acelerar Testes Unitários e Integrados com Spring Boot e API Oficial da Marvel

Thomás da Costa
6 min readJan 4, 2022

Meu Canal no YouTube

https://www.youtube.com/thomasdacosta

Cenário

No mundo atual de desenvolvimento, muitas vezes é necessário efetuar chamadas HTTP para outros serviços ou endpoints específicos necessários para o funcionamento da nossa aplicação.

Quando trabalhamos com microsserviços, algumas vezes é necessário fazer uma orquestração ou uma coreografia para vários outros microsserviços e essas chamadas podem ser em HTTP ou em gRPC.

Quando trabalhamos em arquiteturas mais complexas, e segmentadas divididas por exemplo por áreas de canais e áreas de produtos vamos precisar efetuar integrações entre sistemas.

Podemos também possuir frontends que acessam backends através de um padrão conhecido como BFF.

Não é isso não

Com este cenário, temos um problema quando vamos desenvolver nossos testes unitários: temos dependências externas de outros microsserviços e endpoints dificultando o teste unitário e integrado.

Poderíamos resolver esse cenário com o uso de algum framework de mock de objetos mas podemos acabar ocultando lógicas de negócios ou até mesmo não executando um teste próximo do real.

O que é o WireMock?

Para solucionar o problema acima podemos usar o WireMock.

WireMock é um framework que tem como objetivo, efetuar o mock de um serviço externo em HTTP sendo um Mock Server ou Mock de Servidor, simulando uma chamada com seu respectivo verbo HTTP (GET, POST, PUT e etc), headers, códigos de retorno, response body e outro recursos necessários para montar a chamada HTTP.

Vamos ver a nossa aplicação antes de criar os testes

Antes mostrar o exemplo de código do WireMock, vamos analisar a aplicação que será testada.

A aplicação tem como objetivo ser um BFF para a API Oficial da Marvel.

Chupa Thanos

Com essa API, conseguimos obter informações sobre Personagens, HQ´s, Eventos, Histórias e outras informações sobre o Universo da Marvel.

O BFF desenvolvido tem um endpoint denominado /marvel/heros/{name} que busca um Personagem através do nome e retorna suas características, as ultimas 20 HQ´s e Eventos que participou.

Para conseguir utilizar a API da Marvel é necessário efetuar o cadastro no portal para obter as chaves de acesso para a sua aplicação, BFF ou API:

Será necessário gerar um hash com as chaves da API da Marvel para efetuar as chamadas. Na documentação do Portal da Marvel existe uma explicação:

Depois disso baixe o Swagger do site abaixo:

Com o Swagger em mãos, vamos gerar o client para a API da Marvel e seus respectivos objetos usando a biblioteca Feign Client do Spring Cloud. Essa biblioteca facilita o desenvolvimento de chamadas HTTP externas diminuindo a complexidade do código para chamada de API´s mais complexas.

Não vamos entrar no detalhe do funcionamento do Feign Client nesse artigo

Execute os comandos abaixo para gerar o client e os objetos a partir do Swagger:

wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.29/swagger-codegen-cli-3.0.29.jar -O swagger-codegen-cli.jarjava -jar swagger-codegen-cli.jar generate -i marvel-public-api-v1-swagger.json -l spring --library spring-cloud -o marvel

Acesse o GitHub para ver a aplicação completa:

Eu sou o Homem de Ferro

Analisando o código da aplicação

A aplicação é composta pela camada Controller, Service e Feign Client para chamadas da API da Marvel.

Abaixo estamos efetuando a busca de um Personagem através de um nome especifico e efetuando a transformação das informações para um outro objeto, que será encaminhado para a camada Controller.

A classe MarvelApiClient é referente ao Feign Client que acessa diretamente a API da Marvel:

Buscando informações de um Personagem a partir de um nome especifico

Além disso, outros dois métodos efetuam a busca das HQ´s e Eventos do personagem encontrado:

Efetuando a busca das HQ´s de um personagem
Efetuando a busca dos Eventos de um Personagem

Como funciona o WireMock

O WireMock possui uma API fluente para construção dos testes integrados usando a classe WireMock:

API do WireMock

Podemos ler o código acima da seguinte forma:

WireMock.stubFor = crie um mock de um servidor para o seguinte verbo HTTP.

WireMock.get = crie um mock para o verbo GET com o endereço especificado.

willReturn = que irá retornar uma resposta HTTP.

WireMock.aResponse = crie uma resposta HTTP.

withStatus = com um HTTP Status definido.

withHeader =com um header de resposta.

withBody = com um corpo de resposta especifico.

Colocando nosso código em uma frase seria a seguinte:

Crie um mock de um servidor usando o verbo GET que irá retornar uma resposta HTTP com status 200 com um header de resposta no formato JSON e gere um body com JSON de resposta do personagem

Código Fonte dos Testes Integrados com o WireMock

A classe de teste deve possuir a anotação @WireMockTest para definir o servidor e a porta que será inicializado.

No nosso exemplo, o servidor utilizará a porta 8081:

Configuração das classes de Testes

O cenário de teste a seguir, foi criado pensando em um retorno com HTTP Status 200 da API:

Teste com HTTP Status 200

Para cada teste integrado, devemos definir um application.properties com portas diferentes e nome de arquivos diferentes para não receber um erro de porta em uso.

O erro de porta em uso pode acontecer quando um teste termina e um outro é inicializado quando usamos alguma automação ou quando estamos executando dentro de uma esteira de Devops.

A propriedade marvelPublicAPIV1.url define o endereço onde o Feign Client irá efetuar a conexão com a API da Marvel.

Como estamos utilizando o WireMock, iremos configurar o endereço para localhost com a porta especificada dentro da classe de teste:

application.properties do teste integrado

Vamos deixar o teste um pouco mais completo criando um cenário que retorna um HTTP Status 404 quando um Personagem não existe:

Teste com HTTP Status 404

Classe de teste integrado para a camada de Service:

Teste Integrado com a classe Service

Classe de teste integrado para a camada de Controller.

Com esse cenário conseguimos efetuar um teste de ponta a ponta dentro da aplicação:

Teste Integrado de ponta a ponta

Considerações

  • Sempre coloque todos os cenários possíveis dos seus testes integrados
  • Sempre teste todos os HTTP Status que a integração possa retornar
  • Separe logicamente os seus testes integrados de acordo com as camadas da aplicação
  • Independente que o teste seja integrado ou unitário, uma boa prática é sempre ter um application.properties por teste para deixar bem separado as configurações e o teste ser independente

Repositório do GitHub

O código fonte desse artigo está na branch wiremock-test.

Até a próxima!

--

--

Thomás da Costa

📺+ de 20 anos gerando código fonte em Java, Arquiteto Java, Desenvolvedor Java, Professor Universitário e Colecionador de Videogames