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.
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.
Veja que dois arquivos foram criados, o .rspec e uma pasta chamada spec com o arquivo spec_helper.rb.
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:
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.
- Link que vamos utilizar junto do método GET para obter a lista de usuários.
- Esse endpoint nos retorna um código 200, caso tenha sucesso.
- Este vamos utilizar junto do método GET para obter um usuário (int).
- Esse endpoint nos retorna um código 200, caso tenha sucesso.
- Link que vamos utilizar junto do método POST para criar um usuário.
- Ele que cria um novo usuário através do json informado e retorna um outro json + status code 201, caso tenha sucesso.
- Este vamos utilizar junto do método PUT para atualizar ou criar um usuário (int).
- Ele atualiza um usuário existente ou cria um novo caso não exista ao passarmos um json e nos retorna essa informação + status code 200, caso tenha sucesso.
- Link que vamos utilizar junto do método DELETE para remover um usuário (int)
- Ele remove um usuário existente e nos retorna status code 204, caso tenha sucesso.
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:
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
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:
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:
Agora, dois testes foram executados e ambos passaram.
Criando um novo usuário
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.
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:
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:
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:
Show! Agora conseguimos finalizar todos os testes propostos utilizando HTTParty e Rspec.
Nossos arquivos ficaram assim:
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!