Microservices: testando com REST-assured

 

O que são microservices?

Microservices. Mais uma dentre as várias buzzwords do mundo da tecnologia. Mas o que seria mesmo um microservice?

De maneira geral, um microservice é um estilo arquitetural. Neste estilo, em vez de sua aplicação ser um grande monolito (em uma aplicação Java web, por exemplo, um único arquivo .war), ela é particionada em partes menores independentes e que colaboram entre si. Assim, cada serviço/componente pode ser implementando na tecnologia que se desejar, ter seu próprio banco de dados, ser deployado independentemente de outros etc.

Estes serviços podem se comunicar entre si de diversas formas: de forma assíncrona utilizando filas de mensagem ou de forma síncrona utilizando SOAP, chamadas remotas (RPC) ou utilizando HTTP/REST. Esta última forma, utilizando HTTP/REST, tem se tornado cada vez mais comum. Por meio dela, o serviço expõe uma API simples para que outros serviços o chamem a fim de realizar alguma operação.

É preciso agora, obviamente, não só garantir que as regras de negócios dos microservices funcionem, mas também que eles respondam de forma esperada/adequada às chamadas realizadas por outros serviços. Enquanto que para o primeiro caso fazemos testes unitários, no último caso, precisamos testar a API REST exposta para uso o externo.

Em ação o REST-assured

O REST-assured é um framework para testar e validar serviços REST. Ele utiliza a linguagem Java e se integra perfeitamente com o JUnit para a escrita dos testes.

O REST-assured permite:

  • Validar o retorno de APIs JSON e XML;
  • Validar JSON utilizando o JsonSchema;
  • Validar XML utilizando validação de DTD ;
  • Validar os cabeçalhos e o status de resposta HTTP, status da resposta;
  • Testar o tempo de resposta de uma requisição
  • Construir validações que utilizem cookies;
  • Testar com diversos métodos de requisição HTTP: GET, PUT, POST, DELETE, CONNECT etc;
  • Testar mecanismos de autenticação: Basic, baseado em formulário de login/senha, OAuth etc.

Portanto utilizamos o REST-assured para fazer chamadas ao nosso microservice e verificar se o retorno é o esperado. Vamos mostrar um exemplo prático de funcionamento do REST-assured.

Exemplo

Vamos utilizar o REST-assured para fazer o testes de um microservice de filmes (/filmesapi). O código desta implementação encontra-se no meu GitHub.

Para o exemplo deste post, vamos validar as seguintes funcionalidades exposta por nossa API:

  • GET /filmesapi/filmes: retorna a lista de todos os filmes existentes
  • GET /filmesapi/filmes/id : retorna um filme específico (id é um número que identifica um filme)

O retorno das chamadas vem no formato JSON. Abaixo está um exemplo com o retorno da chamada a todos os filmes:


{
    "dados": [
        {
            "id": 1,
            "nome": "A Grande Muralha",
            "atores": [
                {
                    "id": 1,
                    "nome": "Matt Damon"
                },
                {
                    "id": 2,
                    "nome": "Willem Dafoe"
                }
            ]
        },
        {
            "id": 2,
            "nome": "Perdido Em Marte",
            "atores": [
                {
                    "id": 1,
                    "nome": "Matt Damon"
                }
            ]
        }
    ],
    "quantidade": 4
}

O REST-assured é construído em cima de uma DSL poderosa. Ao utilizá-la, fica simples fazer chamadas HTTP e verificar o retorno das mesmas utilizando matchers – aqui podemos utilizar os matchers do próprio framework como podemos, também, utilizar matchers do Hamcrest. Vamos demonstrar alguns usos da DSL do REST-assured.

  • Verificando cabeçalhos de resposta

    Podemos verificar os cabeçalhos de resposta de uma chamada a um microservice HTTP REST.  Por exemplo, o código abaixo valida se a chamada vem com um status code HTTP 200 OK e se o Content-type é application/json.


 @Test
 public void todosFilmesVerificaCabecalhosResposta() {
   get("/filmesapi/filmes").
     then().
     statusCode(200).
     and().
     contentType(ContentType.JSON);
 }

Observe que é feita uma chamada GET à url de destino /filmesapi/filmes (por padrão, o REST-assured assume que o endereço da aplicação é localhost:8080) e então (then()) verificamos se o código de resposta é 200 (HTTP OK) e (and()) se o Content-Type é JSON – as linhas destacadas no exemplo anterior. Se alguma dessas validações falhar, o teste não passa. Veja, ainda, que a DSL é bastante descritiva e clara em sua intenção.

Nota: os métodos utilizados neste exemplo (assim como os dos exemplos a seguir) são métodos estáticos da classe <code>RestAssured</code>. Seguindo a orientação do guia de uso do REST-assured e com intuito de aumentar a legibilidade, foi feito um import estático dessa classe. Portanto leve isso em consideração ao ler os exemplos de código desse post.

  • Validando dados da resposta

Podemos validar se a resposta retornada pelo nosso microservice contém os campos desejados. No nosso exemplo, o JSON vem com o campo dados (a lista de todos os filmes) e o campo quantidade (que é a quantidade de filmes existentes). Verificar a existência desses atributos é simples.


 @Test
 public void todosFilmesRetornaListaFilmesEQuantidade() {
   get("/filmesapi/filmes").
     then().
     body("dados", notNullValue()).
       and().
     body("dados", not(empty())).
       and().
     body("quantidade", notNullValue());
 }

O que foi feito, portanto, foi checar se os atributos dados e quantidade estão presentes no corpo da resposta (método body()). Observe, também, que utilizamos matchers Hamcrest (not(empty()) em conjunto com a API DSL do Rest-assured.

  • Utilizando o JsonPath para recuperar valores

O JsonPath faz parte da implementação do Rest-assured. Ele funciona como uma alternativa ao uso do XPath – o JsonPath é o XPath para objetos JSON. Por exemplo, podemos usar o JsonPath para recuperar a lista de filmes e depois aplicar validações em cima dessa lista


 @Test
 public void todosFilmesVerificaAtributosFilmes() {
     List<Filme> filmes = get("/filmesapi/filmes").
                           getBody().
                           jsonPath().
                           getList("dados", Filme.class);
 
     assertThat(filmes, everyItem(hasProperty("id", notNullValue())));
     assertThat(filmes, everyItem(hasProperty("nome", notNullValue())));
     assertThat(filmes, everyItem(hasProperty("sinopse", notNullValue())));
     assertThat(filmes, everyItem(hasProperty("atores", not(empty()))));
 }

O método jsonPath() nos permite trabalhar a resposta para acessar atributos da mesma e converter para o objeto desejado.

Conclusão

O Rest-assured é um framework poderoso para testar microservices e APIs baseadas em HTTP REST. Usá-lo em conjunto com frameworks de testes, como o JUnit, permite que os testes criados com ele sejam executados como parte do mecanismo de integração/entrega contínua.

Lembrando que todo o código do exemplo desse post está disponível em meu GitHub.

Aprenda mais sobre o REST-assured lendo o post Testando com REST-assured: Parte II.

  • Bruno Nascimento

    Muito bom seu artigo, quando estava começando a fazer testes usando REST-assured me ajudou muito.

    • Que bom @disqus_DSb2zLs40L:disqus! Feedbacks assim me motivam ainda mais a continuar escrevendo no blog! Abraços!