Testando APIs com HTTParty e Rspec

Já pensou em testar suas APIs antes de implementar sua adoção? No artigo de hoje você vai ver como testar APIs com duas ferramentas muito úteis: HTTParty e Rspec.

O que você vai ver nesse artigo:

  • Requisitos
  • O que é HTTParty?
  • Mas, o que é Rspec?
  • Por que Testar APIs?
  • Instalando as gems HTTParty e Rspec
  • Iniciando um projeto
  • O que vamos testar?
  • Voltando ao código
  • Primeiro teste – listando todos os usuários 
  • Scripts de testes nos endpoints
  • Recuperando a informação de apenas um usuário 
  • Criando um novo usuário 
  • Atualizando um usuário
  • Removendo um usuário

Requisitos

  • Instalação do Ruby
    • Windows
    • Ubuntu/Debian: sudo apt-get install ruby-full
    • CentOS/Fedora: sudo yum install ruby
    • Arch/Manjaro: sudo pacman -S ruby
    • MacOS: brew install ruby
      • Precisa-se do Homebrew instalado
  • Instalação do Bundler (controla dependências de projetos Ruby)
    • no terminal, após a instalação do Ruby, executar: gem install bundler

Antes de começar, precisamos recapitular o que é HTTParty e Rspec.

O que é HTTParty?

O HTTParty é uma gem utilizada para realizar requisições de verbos HTTP (Post, Get, Put e Delete) de forma simples em web services

Com essa gem, conseguimos realizar desde testes simples (analisando o status code, tempo de execução e campos específicos de uma resposta do serviço) como verificar se regras de negócios complexas funcionam como especificado.

Mas, o que é Rspec?

Já o Rspec é uma ferramenta de desenvolvimento e testes para a linguagem Ruby e que utiliza o conceito de BDD (behavior-driven development) na criação de testes de aplicações. 

Através do Rspec, pode-se testar aplicações nativas (Ruby on Rails) ou em conjunto com outras ferramentas, APIs, Web Apps, entre outras. 

Procura-se utilizar algumas boas práticas quando escolhemos esse tipo de ferramenta para testar nossas aplicações, por exemplo:

  • Escrever casos de testes pequenos, legíveis e se possível, atômicos;
  • Descrever os cenários de forma que o time entenda e consiga trabalhar futuramente seja executando, ou dando manutenção;
  • Agrupar cenários utilizando alguma lógica que faça sentido: funcionalidades parecidas;
  • Evitar uso excessivo de “step by step”. Procuramos descrever os cenários de forma que agregue informações à camada de negócios.

Por que Testar APIs?

Caso tenha interesse em uma leitura complementar, fique a vontade para acessar o meu outro artigo sobre testes com APIs: teste de APIs com Python e Pytest

Nesse artigo, você encontrará explicações mais detalhadas sobre os verbos HTTP e bons motivos que talvez o convença a utilizar esses tipos de testes no seu projeto.

Agora vamos lá!

Instalando as gems HTTParty e Rspec

Caso queira instalar a gem globalmente, basta executar os comandos gem install httparty e gem install rspec no terminal. Porém, caso prefira utilizar de forma local entre projetos, podendo assim utilizar várias versões (uma diferente para cada projeto), basta adicioná-las ao Gemfile do seu projeto e executar o comando bundle install no diretório raiz do mesmo.

Em caso de problemas com permissão (Mac e Linux) ao executar os comandos acima, basta executar no terminal o comando (e adicionar ao seu bashrc) export GEM_HOME=$HOME/.gem que os problemas, teoricamente, devem desaparecer.

Iniciando um projeto

Caso tudo tenha sido instalado com sucesso até aqui, basta criar uma pasta para nosso projeto (eu criei dentro de meus documentos uma pasta chamada teste_httparty), e, dentro dela, executar o comando rspec –init.

Esta imagem mostra a saída padrão quando usamos o comando rspec --init: foram criados 2 arquivos, o .rspec na pasta raiz e o spec_helper.rb dentro da pasta spec.

Veja que dois arquivos foram criados, o .rspec e uma pasta chamada spec com o arquivo spec_helper.rb.

Esta imagem mostra apenas a estrutura de arquivos e pastas no início do projeto.

O próximo passo é criar o arquivo Gemfile na raiz do projeto com as informações:

source 'https://rubygems.org'
 
gem 'rspec'
gem 'httparty'

Execute o comando bundle install no terminal:

Esta imagem exibe o terminal instalando as dependências após o comando.

Remova os comentários do seu spec_helper e adicione os imports para trabalhar de fato com o HTTParty:

require 'httparty'
require 'httparty/request'
require 'httparty/response/headers'
 
RSpec.configure do |config|
 config.expect_with :rspec do |expectations|
   expectations.include_chain_clauses_in_custom_matcher_descriptions = true
 end
 config.mock_with :rspec do |mocks|
   mocks.verify_partial_doubles = true
 end
 config.shared_context_metadata_behavior = :apply_to_host_groups
end

O que vamos testar?

Antes de prosseguir com o código, vamos verificar os endpoints para que possamos criar testes mais assertivos. O site REQ | RES disponibiliza endpoints gratuitamente, onde podemos nos basear para construir nossos scripts.

Resumindo, vamos realizar um CRUD com esse endpoint, adicionando, removendo, atualizando e criando usuários. Um usuário possui nome (string) e job (string) na criação e logo após vai possuir id (int) e createdAt (timestamp).

Voltando ao código

Vamos criar uma pasta na raiz chamada services, nela, para cada novo elemento do crud, cria-se um arquivo informando essas características do endpoint ao HTTParty. Logo, criaremos a pasta services e dentro dela um arquivo chamado users_service.rb:

module User
   include HTTParty
   base_uri 'https://reqres.in'
   format :json
end

O código acima é praticamente autoexplicativo. Criamos um módulo para a entidade que vamos testar (User), importamos a gem HTTParty, definimos uma uri base e informamos que vamos trocar informações através de json.

No arquivo spec_helper, importe seu novo módulo e inclua-o dentro da seção de configuração do RSpec:

require 'httparty'
require 'httparty/request'
require 'httparty/response/headers'
 
require_relative '../services/user_service.rb'
 
RSpec.configure do |config|
 include User
 config.expect_with :rspec do |expectations|
   expectations.include_chain_clauses_in_custom_matcher_descriptions = true
 end
 config.mock_with :rspec do |mocks|
   mocks.verify_partial_doubles = true
 end
 config.shared_context_metadata_behavior = :apply_to_host_groups
end

Primeiro teste – listando todos os usuários 

Na pasta /spec, crie um arquivo chamado get_spec.rb e adicione o código:

describe 'agrupando os metodos de verbo GET' do
 
   it 'meu primeiro teste - listando users' do
       @users = User.get('/api/users?page=2')
       puts @users
   end
 
end

O describe, além de fornecer informações daquele módulo que está sendo testado, serve para agrupar testes, armazenar variáveis de sessão etc. O it seria o teste de fato, o que vamos testar, ou seja, primeiro teste que vai listar usuários. Guardei a informação do get na variável @users e a imprimi logo em seguida. Execute o comando rspec na pasta raiz e veja o resultado:

Ao executar o comando rspec na pasta raiz, deve-se verificar a saída com o payload contendo informações como page, per_page, total, total_pages, data, etc.

Agora, vamos fazer de fato o primeiro teste. Remova o puts e adicione uma verificação se o status code retornado é igual a 200 (como combinado previamente) e execute o comando rspec spec/get_spec.rb:

describe 'agrupando os metodos de verbo GET' do
 
   it 'meu primeiro teste - listando users' do
       @users = User.get('/api/users?page=2')
       expect(@users.code).to eq(200)
   end
 
end
a imagem mostra que o comando mostra que o resultado do teste com HTTParty e Rspec passou e que ele foi executado em menos de um segundo.

Show! Agora conseguimos executar um teste utilizando as duas ferramentas propostas. 

Scripts de testes nos endpoints combinados

Dando sequência ao artigo, continuaremos desenvolvendo os scripts de testes nos endpoints combinados:

  • GET para obter apenas um usuário; 
  • POST para criação; 
  • PUT para atualização;
  • DELETE para remoção.   

Toda a informação necessária para análise dos endpoints, encontra-se disponível no site REQ. Para que o conteúdo seja absorvido com maior assertividade, indico que acesse o link e use alguns minutos estudando a API, suas chamadas e retornos.

Recuperando a informação de apenas um usuário 

O endpoint utilizado para esse teste seria a combinação da base_uri, já definida no primeiro artigo com o final /api/users/_id, onde o _id representa o id único (inteiro) do usuário que vamos buscar. Veja o resultado exibido pelo site:

Essa imagem exibe o resultado desse request no site utilizado: response igual a 200 e um dicionário com as informações do usuário.

Como vamos realizar outro GET, podemos inserir outro teste dentro do arquivo get_spec.rb

  • Crie outro teste começando pelo modelo usado no script anterior it ‘nome do teste’ do -> teste -> end
  • Realize o request e guarde a informação em uma variável 
  • Verifique se o status code (200), id (2) e primeiro nome (Janet) são retornados de acordo com o esperado: 
it 'meu segundo teste - verificando um usuario' do
       @user = User.get('/api/users/2')
       expect(@user.code).to eq(200)
       expect(@user['data']['id']).to eq(2)
       expect(@user['data']['first_name']).to eq("Janet")
   end

Nosso script completo fica assim:

describe 'agrupando os metodos de verbo GET' do
 
   it 'meu primeiro teste - listando users' do
       @users = User.get('/api/users?page=2')
       expect(@users.code).to eq(200)
   end
 
   it 'meu segundo teste - verificando um usuario' do
       @user = User.get('/api/users/2')
       expect(@user.code).to eq(200)
       expect(@user['data']['id']).to eq(2)
       expect(@user['data']['first_name']).to eq("Janet")
   end
 
end

Na pasta raiz, execute o comando rspec novamente e veja o resultado:

A imagem exibe a saída do terminal com a quantidade de testes executados, tempo de execução e resultado.

Agora, dois testes foram executados e ambos passaram.

Criando um novo usuário 

A imagem exibe o endpoint /api/users, um dicionário com chaves name e job, o response (201) e o dicionário de resposta com name, job, id e createdAt.

Como pode ser visto, para criar um usuário, precisamos inserir os campos nome e job através de um dicionário, que é uma estrutura de dados bastante utilizada em requisições.

O passo a passo é:

  • Criar um arquivo chamado post_spec.rb
  • Crie um teste começando pelo modelo usado no script anterior it ‘nome do teste’ do -> teste -> end
  • No teste, crie uma variável que contenha esse novo user conforme combinado.
  • No request, informe a variável como parâmetro (body) e mude o verbo para post
    • Não esqueça de guardar o request em outra variável
  • Verifique se o status code (201), id (não nulo), name e job vêm de acordo com o esperado.
A imagem mostra o novo arquivo post_spec.rb dentro da pasta spec.
describe 'agrupando os metodos de verbo POST' do
 
   it 'meu terceiro teste - adicionando users' do
       @new_user = {
           name: "Testerson",
           job: "QA"
       }
 
       @request = User.post('/api/users', :body => @new_user)
       expect(@request.code).to eq(201)
       expect(@request["id"]).not_to be nil
       expect(@request["name"]).to eq(@new_user[:name])
       expect(@request["job"]).to eq(@new_user[:job])
 
   end
 
end

Nota-se que nesse teste, foi preciso enviar as informações do novo usuário através do parâmetro body. Agora, além de verificar status code, também comparamos se a informação inserida no body foi a mesma de retorno e se o id do novo usuário não é nulo.

Nota: quem tiver interesse em pesquisar sobre as comparações disponíveis no Rspec, pode verificar aqui.

Agora, rode o teste apontando para o novo script com o comando rspec spec/post_spec.rb (só vai funcionar se você deixar os nomes e pastas iguais ao do artigo) e veja o resultado:

A imagem exibe o resultado da execução do teste.

Atualizando um usuário

Agora ficou fácil, pois, como pode ser visto na figura acima, para atualizar um indivíduo, deve-se passar seu id na URL e ainda passar informações sobre name e job em um dicionário, como feito no teste de criação. Os retornos são basicamente os mesmos: response (200), name e job atualizados, além da data de atualização.

O passo a passo é:

  • Criar um arquivo chamado put_spec.rb
  • Crie um teste começando pelo modelo usado nos script anteriores it ‘nome do teste’ do -> teste -> end
  • No teste, crie uma variável que contenha as novas informações
  • No request, informe a variável como parâmetro (body) e mude o verbo para put
    • Não esqueça de guardar o request em outra variável.
  • Verifique se o status code (200), name e job vêm de acordo com o esperado:
describe 'agrupando os metodos de verbo PUT' do
 
   it 'meu quarto teste - atualizando users' do
       @updated_user = {
           name: "Testerson da Silva",
           job: "Automation QA"
       }
 
       @request = User.put('/api/users/2', :body => @updated_user)
       expect(@request.code).to eq(200)
       expect(@request["name"]).to eq(@updated_user[:name])
       expect(@request["job"]).to eq(@updated_user[:job])
 
   end
 
end

Ficou bem parecido com o teste passado, concorda? Agora execute o comando rspec spec/put_spec.rb e veja o resultado:

A imagem exibe o resultado da execução do teste.

Removendo um usuário 

Finalmente, o último script de teste deste artigo. Agora, vamos remover um usuário passando apenas a uri padrão + id. O retorno seria apenas o código 204. 

Veja que esse site que estamos usando para conhecer as ferramentas HTTParty e Rspec é simples e não nos dá muitas informações que geralmente temos no mundo real, ele apenas simula que estamos removendo esse usuário. Por isso, sempre fique de olho nas regras de negócio que o seu time vai definir para esse tipo de endpoint. 

O passo a passo é:

  • Criar um arquivo chamado delete_spec.rb
  • Crie um teste começando pelo modelo usado nos script anteriores it ‘nome do teste’ do -> teste -> end
  • No request mude o verbo para delete.
    • Não esqueça de guardar o request em outra variável.
  • Verifique se o status code (204) vem de acordo com o esperado.
describe 'agrupando os metodos de verbo DELETE' do
 
   it 'meu quinto teste - removendo users' do
 
       @request = User.delete('/api/users/54')
       expect(@request.code).to eq(204)
 
   end
 
end

Agora, execute o comando rspec spec/delete_spec.rb e veja o resultado:

A imagem exibe o resultado da execução do teste.

Show! Agora conseguimos finalizar todos os testes propostos utilizando HTTParty e Rspec. 

Nossos arquivos ficaram assim:

Essa imagem mostra a estrutura de arquivos do nosso projeto, um arquivo dentro da pasta service, 5 dentro da pasta spec e mais 3 arquivos na pasta raiz.

Na próxima parte desta série de artigos, vamos configurar o projeto para que possamos mostrar relatórios com um visual bem interessante e que podem ser utilizados até em reuniões. Além disso, vamos inserir tags nos nossos testes para não informar o caminho completo do script e vamos inserir contexto de setup e teardown para organizar nossa suíte de testes. 

Até mais!

Homem preto comemorando na frente de um computador com códigos.
Marlon de Alencar
Analista de Testes
Engenheiro de computação, mestrando em Ciências de Computação e jogador de Dota nas horas vagas.

Este site utiliza cookies para proporcionar uma experiência de navegação melhor. Consulte nossa Política de Privacidade.