DEV Community

Isadora Rocha
Isadora Rocha

Posted on

REspec Estrutura de Teste em Ruby on Rails

Considere a aplicação já criada

  • Nosso model é Article, com os atributos title(string) e content(text)

⇾ Utilizando rails c no terminal

Criaremos um array de hashes utilizando rails c para um teste rápido

blog(dev)* articles = [
blog(dev)*   {title: 'art 1', content: 'conteudo do art 1'},
blog(dev)*   {title: 'art 2', content: 'conteudo do art 2'},
blog(dev)*   {title: 'art 3', content: 'conteudo do art 3'}
blog(dev)> ]
Enter fullscreen mode Exit fullscreen mode

⇾ Utilizando arquivo seeds.rb

O arquivo seeds.rb é usado para configurar um ambiente de desenvolvimento ou teste com dados de exemplo, ou para fornecer dados iniciais ao banco de dados de produção. Ao executar o comando rails db:seed, ele rodará o arquivo e insere os dados no banco de dados.

No caso, o uso do rails c, os dados são imediatamente criados no banco de dados, mas essa ação não fica registrada em nenhum arquivo. Portanto, é adequado para testes rápidos ou manipulações de dados interativas que você não precisa necessariamente registrar para uso futuro.

Agora, deve-se colocar o mesmo array de hashes dentro do arquivo seeds.rbpara ficar registrado.

Image description

E, por fim, executar Article.create(articles) no rails c.


⇾ Agora, vamos ao controller

  1. Criar uma pasta, dentro da pasta controllers, chamada api. Logo após, criar outra pasta chamada v1.
    É uma boa prática para não deixar tudo junto na aplicação.

  2. Agora, no arquivo articles_controller.rb, devemos alterar a class ArticlesController < AplicattionController para:

class Api::V1::ArticlesController < ActionController::API
Enter fullscreen mode Exit fullscreen mode
  1. Dentro do método index, adicionar um render json - um retorno para a requisição GET da aplicação.
def index
    render json: { message: 'carregado'}
end
Enter fullscreen mode Exit fullscreen mode

CÓDIGO COMPLETO

class Api::V1::ArticlesController < ActionController::API
  def index
    Article.all
    render json: { message: 'carregado'}
  end
end
Enter fullscreen mode Exit fullscreen mode

GET 127.0.0.1:3000/articles no POSTMAN.
Image description

OBS.: talvez tenha ocorrido um erro, deve-se configurar as rotas no arquivo routes.rb.

resources :articles, only: :index
Enter fullscreen mode Exit fullscreen mode

⇾ Agora, vamos ao routes

Como não iremos utilizar as views, precisamos especificar um formato obrigatório (constraints), no caso utilizaremos json e xml, como exemplo.

Em config > routes.rb, vamos precisar definir namespaces e constraints.

namespace :api, constraints: ->(req) { %w[json].include? req.format } do
    namespace :v1 do
      resources :articles, only: :index
    end
  end
Enter fullscreen mode Exit fullscreen mode
  • O constraints ficará na mesma linha do no namespace :api para que todas as rotas dentro dessa pasta sigam a mesma regra.

⇾ GEMFILE
Dentro do group :development do end, adicionar a gem do RSpec

# Testes - [https://github.com/rspec/rspec-rails]
  gem 'rspec-rails', '~> 7.0.0'
Enter fullscreen mode Exit fullscreen mode

Em seguida, no terminal rodar bundle install para atualizar a gem. E por fim, executar rails g rspec:install.


⇾ SPEC
Dentro da pasta spec
, criaremos uma pasta chamada request, e dentro dessa pasta, criaremos um arquivo chamada: articles_spec.rb.

require 'rails_helper'
Enter fullscreen mode Exit fullscreen mode

Importar o arquivo rails_helper.rb, carrega o ambiente de teste e configurações necessárias para rodar os testes.

RSpec.describe 'Articles' do
end
Enter fullscreen mode Exit fullscreen mode

Definir um grupo de testes para a entidade Articles.
RSpec.describe é a forma de agrupar e descrever testes em RSpec.

before(:each) { Article.create(title: 'art 2', content: 'conteudo do art 2') }
Enter fullscreen mode Exit fullscreen mode

Criar um article com o título 'art 2' e o content 'conteúdo do art 2' antes de cada teste ser executado.

  • *Por quê?: * garantir que cada teste dentro desse grupo comece com um estado consistente, com pelo menos um artigo salvo no banco de dados.
require 'rails_helper'

RSpec.describe 'Articles' do
  before(:each) { Article.create(title: 'art 2', content: 'conteudo do art 2') }

(você está aqui)
  context "GET api/v1/articles" do

  end
end
Enter fullscreen mode Exit fullscreen mode

Dentro do bloco RSpec.describe, adicionar o bloco context "GET api/v1/articles" do end

Serve para agrupar testes relacionados à rota **GET api/v1/articles**. contexté usado para organizar os testes em torno de um cenário ou contexto específico.

Agora, adicionaremos outro bloco **it 'responds with status Ok' do end**

...
context "GET api/v1/articles" do
(você está aqui)
    it 'responds with status Ok' do

    end
  end
Enter fullscreen mode Exit fullscreen mode

Esse bloco define um teste individual. Dentro do bloco it é uma descrição do que o teste deve verificar, neste caso, se a resposta da rota GET api/v1/articles.json retorna um status Ok (200).

Dentro do bloco it, deve adicionar essas duas linhas:

context "GET api/v1/articles" do
    it 'responds with status Ok' do
(você está aqui)
      get '/api/v1/articles.json'
      expect(response).to have_http_status(:ok)
    end
Enter fullscreen mode Exit fullscreen mode

O get '/api/v1/articles.json', faz uma requisição HTTP GET para a rota /api/v1/articles.json.. Esse método simula uma chamada à API.

O expect(response).to have_http_status(:ok), verifica se a resposta da requisição tem o status :ok (200). Se a API responder com um status diferente, o teste falhará.

Por fim, adicionar mais um bloco it (não é dentro do bloco it anterior).

...
it 'responds with correct persistes article json' do
      get '/api/v1/articles.json'
      expect(response.body).to include('art 2')
      expect(response.body).to include('conteudo do art 2')
end
Enter fullscreen mode Exit fullscreen mode

O it 'responds with correct persisted article json' do, define outro teste individual, que verifica se o JSON retornado pela API contém os dados do artigo que foi criado no before.

O expect(response.body).to include('art 2'), verifica se o corpo da resposta (response.body) inclui o título 'art 2'.

*⇾ CÓDIGO COMPLETO *

require 'rails_helper'

RSpec.describe 'Articles' do
  before(:each) { Article.create(title: 'art 2', content: 'conteudo do art 2') }

  context "GET api/v1/articles" do
    it 'responds with status Ok' do
      get '/api/v1/articles.json'
      expect(response).to have_http_status(:ok)
    end

    it 'responds with correct persistes article json' do
      get '/api/v1/articles.json'
      expect(response.body).to include('art 2')
      expect(response.body).to include('conteudo do art 2')
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

RETORNANDO AO CONTROLLER
Ao invés de:

class Api::V1::ArticlesController < ActionController::API
  def index
    Article.all
    render json: { message: 'carregado'}
  end
end
Enter fullscreen mode Exit fullscreen mode

Vamos alterar para que a API retorne todos os dados, e que seja status OK.

class Api::V1::ArticlesController < ActionController::API
  def index
    render json: Article.all, status: :ok
  end
end
Enter fullscreen mode Exit fullscreen mode

⇾ Para testar o RSpec
No terminal, executar rspec

➜  blog git:(main) ✗ rspec
.

Finished in 0.05506 seconds (files took 2.19 seconds to load)
1 example, 0 failures

➜  blog git:(main) ✗ 
Enter fullscreen mode Exit fullscreen mode

Essa mensagem indica que ocorreu tudo correto.


*⇾ Para testar no Postman *
Como definimos como json e xml, as rotas devem ser:

  • GET 127.0.0.1:3000/articles.json ou,
  • GET 127.0.0.1:3000/articles.xml

É isso. Obrigada!

REFERÊNCIAS:
Api app/Rails (Rails Guides): https://guides.rubyonrails.org/api_app.html
Routing/Rotas (Rails Guides): https://guides.rubyonrails.org/routing.html
RSpec Rails: https://github.com/rspec/rspec-rails
Rails Status codes: http://www.railsstatuscodes.com/
**Action Controller API: **https://api.rubyonrails.org/classes/ActionController/API.html
**Introdução a Api com Rails - primeiros passos: **https://www.youtube.com/watch?v=cj3GIO2CETo

Top comments (0)