Testando com REST-assured – Parte II

No post anterior demonstramos as funcionalidades básicas de um teste de microservices utilizando o framework REST-assured. Apresentamos alguns métodos básicos e fizemos asserções para verificar o resultado de nossas chamadas.

Basicamente o que fizemos foi utilizar o método HTTP GET. Agora, vamos fazer uso dos métodos PUT e DELETE. Além disso, vamos mostrar como escrever testes para aplicações que requerem autenticação.

Para os exemplos desse post, vamos continuar utilizando nosso microservice de filmes (/filmesapi). Só que agora vamos trabalhar a manipulação de atores dos filmes:

  • GET /filmesapi/atores: retorna a lista de todos os atores existentes
  • GET /filmesapi/atores/id : retorna um ator específico (id é um número que identifica um ator)
  • PUT /filmesapi/atores: grava um novo ator
  • DELETE /filmesapi/atores/id: remove um ator existente

Lembrando que todo o código deste e do post anterior pode ser acessado no meu Github: https://github.com/andrethiago/filmesapi.

Testando o envio de dados com PUT

Quando um novo ator é criado, por meio do método HTTP PUT, a API do nosso microservice retorna o código HTTP 201 e a mensagem “Ator criado com sucesso”. Essa chamada espera receber os dados do ator criado via JSON – nosso objeto ator é muito simples; basta passarmos um nome para o mesmo ser criado. O código abaixo demonstra a chamada a nossa API.


@Test
public void gravaNovoAtor() {
	given().
		contentType(JSON).
		body("{\"nome\" : \"Robert De Niro\"}").
		put("/filmesapi/atores");
		
}

Essa é a primeira parte do nosso teste, chamando o nosso microservice. Agora, para se tornar um teste de verdade, precisamos da verificações. Então vamos adicionar a verificação do código de resposta HTTP e da mensagem retornada.


@Test
public void gravaNovoAtor() {
	given().
		contentType(JSON).
		body("{\"nome\" : \"Robert De Niro\"}").
		put("/filmesapi/atores").
		then().
		statusCode(201).
		and().
		body(equalTo("Ator criado com sucesso."));
}

As linhas de código destacadas fazem as verificações necessárias – código HTTP da resposta e verifica a mensagem retornada.

Removendo dados com o DELETE

O código de teste para o DELETE é muito similar aos já apresentados anteriormente. Observando a descrição de nossa API, o DELETE é feito por id. Para efeitos de simplificação, vamos apagar o ator com identificador igual a 1. Além disso, além das verificações relacionadas a nossa chamada, vamos fazer uma comparação entre o quantitativo de atores antes de nosso DELETE e depois dele – esperamos que a quantidade tenha sido reduzida de 1.

Vamos ao código do DELETE.

@Test
public void apagaAtorExistente() {
	delete("/filmesapi/atores/{id}", 1).
	then().
	statusCode(200).
	and().
	body(equalTo("Ator removido com sucesso"));
}

Observem que as asserções são bem similares àquelas que fizemos até agora. Cabe apenas ressaltar a linha em destaque; veja que estamos fazendo uso do recurso de path parameters do REST-assured, em que é possível associar uma “variável” da url a um valor determinado – nesse caso estamos atribuindo à variável “id” o valor 1.

Para o nosso teste ficar ainda mais completo, podemos verificar a quantidade de atores antes e depois de nossa chamada. Vamos ao código.

@Test
 public void apagaAtorExistente() {
    Integer atoresAntes = 
       get("/filmesapi/atores").then().extract().response().path("quantidade");
 
    delete("/filmesapi/atores/{id}", 1).
    then().
    statusCode(200).
    and().
    body(equalTo("Ator removido com sucesso."));
 
    Integer atoresDepois = 
       get("/filmesapi/atores").then().extract().response().path("quantidade");
    assertTrue(atoresDepois == Integer.valueOf(atoresAntes - 1));
 }

As linhas em destaque adicionam a verificação que torna o nosso teste ainda mais completo: além de verificarmos o código de retorno e a mensagem de resposta ao DELETE – o que por si só já garantiria o sucesso de nossa chamada, verificamos também a quantidade de atores existentes antes e depois da chamada, assegurando que essa quantidade foi diminuída de 1.

Lembrando que em um cenário real, para não dependermos de cenários externos, nosso teste deveria incluir um novo ator e em seguida apagá-lo. Assim o nosso teste seria independente e completo.

Obtendo dados que necessitam de autenticação

Para finalizar, vamos mostrar como usar o REST-assured quando a chamada ao nosso microservice exige autenticação.

Para tornarmos o acesso a nossa API de microservices seguro, vamos utilizar o Spring Security. Adicionamos o código abaixo à configuração da nossa aplicação.

 protected void configure(HttpSecurity http) throws Exception {
   http.
     csrf().disable().
     authorizeRequests().
     anyRequest().
     authenticated().
     and().
     httpBasic();
 }

O código em destaque faz com que todas as requisições a nossa aplicação necessitem de autenticação e autorização para que sejam completadas com sucesso. Observe que a chamada httpBasic() configura o método básico de autenticação com usuário e senha. Uma tentativa de acesso sem que esteja autenticado não será completada; o servidor retorna o código de acesso 401, informando que é necessária autenticação completa para ter acesso ao recurso.

Autenticação exigida ao tentar acessar uma url
Autenticação exigida ao tentar acessar uma url

 

Erro retornado ao tentar acessar sem autenticação
Erro retornado ao tentar acessar sem autenticação

Teste que verifica a necessidade de autenticação

Primeiro, vamos escrever um teste que verifica que é necessária a autenticação ao acessar qualquer url da API de nosso microservice. O código está abaixo.

@Test
public void acessoExigeAutenticacao() {
  get("/filmesapi/filmes").
  then().
   statusCode(401);
}

Portanto a verificação é bem simples: basta checarmos o código HTTP de retorno – 401.

Habilitando o REST-assured para enviar as credenciais de autenticação

Agora vamos modificar nossos testes para que os mesmos levem em conta o mecanismo de autenticação. Vale ressaltar que configuramos um mecanismo básico de autenticação do Spring Security baseado em memória, ou seja, criamos usuários e senhas fictícios que serão utilizados para o Spring Security verificar as credenciais de autenticação.

Vamos lembrar nosso código de teste que recuperava todos os filmes e fazia as asserções necessárias.

  get("/filmesapi/filmes").
   then().
   statusCode(200).
    and().
   contentType(JSON);

Executar esse teste nos retorna falha, pois, o código de retorno não é mais 200 e sim 401 – por causa da autenticação. Vamos então, colocar o código que envia as credenciais da autenticação na chamada a nossa API.

  given().auth().basic("joao", "123456").
   when().
   get("/filmesapi/filmes").
    then().
    statusCode(200).
     and().
    contentType(JSON);

A linha em destaque faz com que as credenciais de autenticação sejam informadas quando pedidas pela aplicação. Com isso, o acesso à url é garantido e o nosso teste passa com sucesso. Simples, não é?

Para não ter que colocar essa linha de código em todos os nosso métodos de teste e ainda assim fazer com que as credenciais de autenticação sempre sejam enviadas, basta criar o método abaixo em nossa classe de testes com a anotação @Before.

 @Before
 public void configuraAutenticacao() {
   RestAssured.authentication = basic("joao", "123456");
 }

Conclusão

Mais uma vez fica clara a simplicidade existente em escrever testes para APIs HTTP REST utilizando o REST-assured. O framework possui uma elegância e muita clareza de intenção em sua DSL. Recomendo fortemente passar a considerá-lo na escrita de seus testes de microservices.

Se ainda não leu, leia o post Microservices: testando com REST-assured para aprender um pouco mais sobre o REST-assured.

Lembrando, uma vez mais que todo o código desses exemplos está disponível aqui em meu GitHub.