DEV Community

Cover image for Como configurar ambiente de testes em Ruby on Rails com RSpec
Paulo Melo
Paulo Melo

Posted on • Edited on

Como configurar ambiente de testes em Ruby on Rails com RSpec

Photo by David Travis on Unsplash

Olá, nesse post eu vou mostrar como configurar o RSpec e demais gems para dar suporte a um ambiente de testes robusto no Ruby on Rails.

Se quiser ver o resultado final das instalações com todos os testes criados, acesse o meu repositório:

GitHub logo peimelo / blog_api

Ruby on Rails 6 course as API showing authentication via devise_token_auth.

Esse post serve para dar apoio ao meu curso de Ruby on Rails 6 - Autenticação via API, que está disponível no YouTube:

Criando o projeto

Vamos criar um novo projeto com banco de dados PostgreSQL e servindo como API (rode no Terminal):

$ rails new blog_api -d postgresql --api -T
Enter fullscreen mode Exit fullscreen mode

Flags:

  • -d postgresql configura o banco PostgreSQL, você pode omitir essa flag caso queira usar o SQLite, que é o banco padrão;
  • --api gera o projeto como API, se omitir essa flag será criado como MVC;
  • -T deixa de gerar os arquivos de testes padrão do Rails que é o Minitest. Caso você já tenha um projeto criado, pode apagar a pasta test.

Adicionando o RSpec

O RSpec é uma opção ao Minitest que vem como padrão no Ruby on Rails. Ele é muito usado e oferece uma sintaxe de fácil compreensão.

Vamos adicionar o RSpec via bundle (ao invés de editar diretamente o Gemfile), porque com esse comando ele adiciona a última versão da gem (rode no Terminal):

$ bundle add rspec-rails -g 'development, test'
Enter fullscreen mode Exit fullscreen mode

Agora rode o comando para criar os arquivos iniciais:

$ rails generate rspec:install
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb
Enter fullscreen mode Exit fullscreen mode

Vamos atualizar o arquivo .rspec para ficar dessa forma:

--require spec_helper
--format documentation
Enter fullscreen mode Exit fullscreen mode

Na primeira linha ele importa o arquivo spec/spec_helper.rb nos testes e o outro comando ele exibe no terminal as mensagens dos testes dessa forma:

Screen Shot 2021-04-18 at 10.01.15

ao invés de pontinhos por arquivo:

Screen Shot 2021-04-13 at 18.20.24

Crie uma pasta chamada support dentro da pasta spec. Agora vamos no arquivo spec/rails_helper.rb e descomente a linha abaixo para que o RSpec importe tudo que estiver dentro da pasta spec/support que vamos precisar mais abaixo nas gems Factory Bot e Database Cleaner:

# ... código existente

Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

# ... código existente
Enter fullscreen mode Exit fullscreen mode

Adicionando o SimpleCov

O SimpleCov mostra a cobertura de código dos nossos testes que é um indicador importante. Vamos adicionar também o simplecov_json_formatter, pois vamos precisar dele para integrar o projeto ao site Code Climate

Rode o comando para adicionar a gem:

$ bundle add simplecov -g 'test' --require false
$ bundle add simplecov_json_formatter -g 'test' --require false
Enter fullscreen mode Exit fullscreen mode

Vamos configurá-lo no projeto, adicionando no início do arquivo spec/rails_helper.rb o trecho de código abaixo:

require 'spec_helper'
require 'simplecov'
require 'simplecov_json_formatter'

SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
  SimpleCov::Formatter::JSONFormatter,
  SimpleCov::Formatter::HTMLFormatter
])

SimpleCov.start do
  add_group 'Config', 'config'
  add_group 'Controllers', 'app/controllers'
  add_group 'Libs', 'lib'
  add_group 'Models', 'app/models'
  add_group 'Serializers', 'app/serializers'
  add_group 'Specs', 'spec'
end

# ... resto do código existente
Enter fullscreen mode Exit fullscreen mode

Aqui estamos fazendo o import e iniciando o SimpleCov, porém eu defini grupos para melhorar a visualização do resultado por abas. Se você desejar poderá adicionar/remover grupos. O resultado final ficará parecido com isso:

Screen Shot 2021-04-19 at 19.38.24

Após rodarmos os testes o SimpleCov irá gerar um relatório que ficará na pasta coverage do nosso projeto, porém é desnecessário que ela esteja no controle de versão do GIT, por isso vamos adicionar uma linha no arquivo .gitignore para ignorá-la:

# ... código existente

/coverage
Enter fullscreen mode Exit fullscreen mode

Adicionando o Shoulda Matchers

O Shoulda Matchers ajuda a fazer alguns testes em apenas uma linha para funcionalidades comuns, que se fossem escritas na mão seriam complexas e sujeitas a erro.

Rode o comando abaixo para adicionar a gem para o group test:

$ bundle add shoulda-matchers -g 'test'
Enter fullscreen mode Exit fullscreen mode

Adicione o código abaixo no final do arquivo spec/rails_helpers.rb e antes do último end:

# ... código existente

  Shoulda::Matchers.configure do |config|
    config.integrate do |with|
      with.test_framework :rspec
      with.library :rails
    end
  end

end # último end do arquivo spec/rails_helpers.rb
Enter fullscreen mode Exit fullscreen mode

Adicionando o Factory Bot

O Factory Bot facilita a fabricação de dados para testes, podendo ser usada para pegar os atributos com valores, criar uma nova instância ou mesmo salvar no banco de dados. Rode o comando para adicionar a gem:

$ bundle add factory_bot_rails -g 'development, test'
Enter fullscreen mode Exit fullscreen mode

Agora vamos configurar a nossa suite de testes para adicionar os métodos do factory_bot, para isso crie um arquivo chamado spec/support/factory_bot.rb e cole nele o trecho abaixo:

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
Enter fullscreen mode Exit fullscreen mode

Dessa forma, ao invés de usarmos nos arquivos de teste o comando FactoryBot.build :article, vamos usar apenas build :article.

Adicionando o Faker

O Faker serve para gerar dados fictícios de diversos tipos. Rode o comando para instalar:

$ bundle add faker -g 'development, test'
Enter fullscreen mode Exit fullscreen mode

Adicionando o Database Cleaner

O Database Cleaner apaga os registros do banco de dados de testes antes de rodar os testes. Para instalar:

$ bundle add database_cleaner-active_record -g 'test'
Enter fullscreen mode Exit fullscreen mode

Agora vamos configurar a nossa suite de testes para adicionar os métodos do Database Cleaner, para isso crie o arquivo spec/support/database_cleaner.rb e cole o trecho abaixo:

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Organizando o Gemfile

Como já adicionamos todas as gems necessárias, eu dou uma organizada no Gemfile para cada uma ficar no seu próprio grupo. Conforme dito antes, eu uso o comando bundle add para que ele adicione a versão da gem ao invés de ficar sem nada.

Veja como fica a organização das gems no Gemfile:

# ... código existente

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem "factory_bot_rails", "~> 6.1"
  gem "faker", "~> 2.17"
  gem "rspec-rails", "~> 5.0"
end

group :test do
  gem "database_cleaner-active_record", "~> 2.0"
  gem "shoulda-matchers", "~> 4.5"
  gem "simplecov", "~> 0.21.2", require: false
end

# ... código existente
Enter fullscreen mode Exit fullscreen mode

Veja que retirei os trechos :group => :test e :groups => [:development, :test] após cada gem ficar no seu grupo.

Adicionando Helpers

Podemos adicionar métodos para simplificar operações e evitar repetições. Tem um helper que eu uso que serve para acessar a resposta json nos meus testes de requests.

Crie um arquivo chamado spec/support/request_helpers.rb e adicione o conteúdo:

module Request
  module JsonHelpers
    def json_response
      @json_response ||= JSON.parse(response.body, symbolize_names: true)
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Vamos alterar novamente o arquivo spec/rails_helper.rb para adicionar depois do end da configuração do Shoulda::Matchers e antes do end final do arquivo a informação para incluir o Request::JsonHelpers:

# ... código existente

  Shoulda::Matchers.configure do |config|
    config.integrate do |with|
      with.test_framework :rspec
      with.library :rails
    end
  end

  config.include Request::JsonHelpers, type: :request
end # último end do arquivo spec/rails_helpers.rb
Enter fullscreen mode Exit fullscreen mode

Dessa forma, podemos usar o helper nos testes de request como no exemplo abaixo (veja no arquivo spec/requests/api/v2/articles_spec.rb que se encontra no repositório de exemplo citado no início desse post):

# ... código existente

  describe 'GET /index' do
    context 'without logged user' do
      it 'renders two articles from distinct users' do
        article
        article_two

        get api_articles_url, headers: {}, as: :json
        expect(json_response.size).to eq 2
      end
    end
  end

# ... código existente
Enter fullscreen mode Exit fullscreen mode

Integrando tudo

Agora que tudo foi configurado, qualquer comando rails generate irá criar o arquivo de testes correspondente.

Vamos criar um CRUD de Articles para testar apenas o model como exemplo. Rode o comando:

$ rails g scaffold Article title:string body:text
Enter fullscreen mode Exit fullscreen mode

Caso você já tenha um projeto existente e está adicionando os testes nesse momento, segundo a documentação do RSpec, você pode rodar o comando abaixo para criar os arquivos de testes do model:

$ rails g rspec:model Article
      create  spec/models/article_spec.rb
      invoke  factory_bot
      create    spec/factories/articles.rb
Enter fullscreen mode Exit fullscreen mode

Temos que rodar o migrate, tanto para development quanto para test, com os dois comandos:

$ rails db:migrate

$ rails db:migrate RAILS_ENV=test
Enter fullscreen mode Exit fullscreen mode

Geração de dados fictícios

Vamos atualizar o arquivo que gera os dados de Article, edite o arquivo spec/factories/articles.rb:

FactoryBot.define do
  factory :article do
    title { Faker::Lorem.sentence }
    body { Faker::Lorem.paragraph(sentence_count: 10) }
  end
end
Enter fullscreen mode Exit fullscreen mode

Dessa forma o Factory Bot e Faker irão gerar dados fictícios e aleatórios para serem testados quando forem solicitados.

Testando o model Article

Vamos atualizar o arquivo app/models/article.rb para adicionar algumas validações:

class Article < ApplicationRecord
  validates :title, presence: true,
                    length: { minimum: 3 },
                    uniqueness: { case_sensitive: false }
  validates :body, presence: true
end
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar nossos testes modificando o arquivo spec/models/article_spec.rb:

require 'rails_helper'

RSpec.describe Article, type: :model do
  subject(:article) { build :article }

  describe 'validations' do
    it { should validate_presence_of(:title) }
    it { should validate_presence_of(:body) }

    it { should validate_length_of(:title).is_at_least(3) }

    it { should validate_uniqueness_of(:title).case_insensitive }
  end
end
Enter fullscreen mode Exit fullscreen mode

Agora rode no terminal o comando rspec e veja o resultado:

Screen Shot 2021-04-18 at 10.01.15

Percebe que o Shoulda Matchers adiciona o texto referente aos testes e cada teste fica com apenas 1 linha.

Outro resultado do comando rspec é que o SimpleCov vai gerar o relatório de cobertura de testes em coverage\index.html. Dê um duplo clique nesse arquivo no seu gerenciador de arquivos (Windows Explorer/Finder) e veja o resultado:

Screen Shot 2021-04-19 at 19.41.01

Bônus: Teste de integração via GitHub Actions

Eu comecei a usar o GitHub Actions ao invés do CircleCI para rodar meus testes antes de fazer o deploy no Heroku.

Crie o arquivo config/database.ci.yml e cole nele o conteúdo abaixo:

Agora crie as pastas e arquivo .github/workflows/ruby.yml e cole nele o conteúdo abaixo:

Verifique e altere, caso necessário, o nome do seu branch no GitHub e a versão do seu Ruby no arquivo .github/workflows/ruby.yml:

# ... código existente

on:
  push:
    branches: [main] # <= AQUI
  pull_request:
    branches: [main] # <= AQUI

# ... código existente

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.0.0 # <= AQUI
          bundler-cache: true

# ... código existente
Enter fullscreen mode Exit fullscreen mode

De agora em diante, ao fazer um push para o GitHub, seu testes irão rodar também no Actions:

Screen Shot 2021-04-20 at 06.39.45

E se tudo ocorrer com sucesso, o deploy será realizado no Heroku, porque eu deixei marcada a opção de Wait for CI to pass before deploy:

Screen Shot 2021-04-20 at 06.51.00

Eu gravei um vídeo sobre isso explicando em detalhes:

Conclusão

Se você chegou até aqui eu te agradeço e parabenizo, porque dessa forma você configurou seu projeto Ruby on Rails para ser seguro e confiante, porque testes são indispensáveis.

Espero que tenham gostado. Um forte abraço.

Top comments (0)