rspec Parte 2 – Testando controllers

Bom dia Pessoal.

Continuando a serie de posts sobre rspec. Estou me acostumando com essa ferramenta, mas de cara já posso dizer que é fantástica, pois você consegue agilizar alguns testes como validar se os cotrollers estão respondendo como esperado, sem a necessidade de dar um refresh no browser.

Hoje irei mostrar como testar controllers.

Pelo que andei pesquisando há um grande debate quando se trata de testar controllers ou não. No meu caso eu acho valido, mas esta é a minha opinião. Isso assegura que todas as rotas e comportamentos da aplicação estejam corretos.

No meu exemplo estarei testando também os acessos ao banco usando a gem FactoryGirl para criar objetos fake. Nós estamos usando também a gem Devise para realizar as autenticações. Vamos lá.

Vou utilizar o projeto toPlay como exemplo, eu não me atenho a detalhes no teste dos controllers somente valido se estes estão respondendo como o esperado (formato, redirect, etc). Quando necessário utilizo o FactoryGirl para criar os objetos para teste.

Meu controller:

class AnswerController < ApplicationController
  def get_answer
    @answer = Alternative.find(params[:answer_id])
    respond_to do |format|
      format.json { render json: { is_correct: @answer.correct } }
    end
  end
end

Basicamente este controller me responde se a alternativa escolhida é a correta, simples. O que eu testo neste caso:

- Crio os objetos para teste nesse caso, o exercicio e uma alternativa correta e incorreta.

RSpec.describe AnswerController, :type => :controller do

  let(:exercise){ FactoryGirl.create(:exercise) }
  let(:correct){ FactoryGirl.create(:alternative) }
  let(:incorrect){ FactoryGirl.create(:alternative_incorrect) }

Descrevo o metodo a ser testado

  describe "GET #get_answer" do

Dou um contexto, neste caso, user não logado

  context 'user not logged' do

E os comportamentos esperados

it 'should redirect user' do
  sign_out
  get :get_answer, { answer_id: correct.id , format: :json }
  expect(response).to be_redirect
end

Neste caso o controller me responde com JSON então eu testo um retorno Html e Json. Não espero um retorno HTML então deve dar um erro.

    context 'when request html' do
      it {
        expect{
          get :get_answer, { exercise_id: exercise.id, answer_id: correct.id }
        }.to raise_error ActionController::UnknownFormat
      }
    end

Testo os retornos para uma resposta certa e uma errada.

    context 'when given a correct answer' do
      before :each do
        sign_in
        correct.correct = true
        correct.save
        get :get_answer, { answer_id: correct.id , format: :json }
      end

      it{ expect(response).to be_success }
      it{ expect(response.content_type).to be_eql 'application/json' }
      it{ expect(response.body).to be_include '"is_correct":true' }

    end

    context 'when given a incorrect answer' do
      before :each do
        sign_in
        incorrect.correct = false
        incorrect.save
        get :get_answer, { answer_id: incorrect.id , format: :json }
      end

      it{ expect(response).to be_success }
      it{ expect(response.content_type).to be_eql 'application/json' }
      it{ expect(response.body).to be_include '"is_correct":false' }

    end

O código completo pode ser visto em:

https://github.com/CristianOliveiraDaRosa/toPlay/blob/master/spec/controllers/answer_controller_spec.rb

Neste modelo, você pode reparar que são testes simples, pois como comentei não me atenho a muitos testes de controller, prefiro apenas validar rotas e respostas esperadas.

Espero ter ajudado.