Aprenda / Ruby on Rails

IntermediárioAula 19 de 2016 min0% da trilha

Testes em Rails: RSpec essencial

Um controller spec testa o controller isolado, sem passar pela rota de verdade; um request spec testa o que o cliente da API realmente recebe.

RSpec é o framework de teste mais usado no ecossistema Rails — substitui o Minitest que vem por padrão no gerador do Rails. Pra uma API, duas camadas de teste cobrem a maior parte do que importa: model spec (a regra de negócio isolada) e request spec (o comportamento HTTP real, de ponta a ponta).

Model spec — validação e associação, sem HTTP nenhum envolvido

spec/models/produto_spec.rb
RSpec.describe Produto, type: :model do
  it "é inválido sem nome" do
    produto = Produto.new(nome: nil, preco: 10)
    expect(produto).not_to be_valid
  end

  it "é inválido com preço menor ou igual a zero" do
    produto = Produto.new(nome: "Teclado", preco: 0)
    expect(produto).not_to be_valid
  end

  it "pertence a uma categoria" do
    expect(Produto.reflect_on_association(:categoria).macro).to eq(:belongs_to)
  end
end

Um model spec testa a classe isolada — sem rota, sem controller, sem servidor rodando. É rápido de rodar e pega exatamente o tipo de regra que já foi coberta na lição de models e migrations: validação e associação.

Request spec — o que o cliente da API realmente vê

spec/requests/pedidos_spec.rb
RSpec.describe "Pedidos", type: :request do
  describe "POST /pedidos" do
    it "cria um pedido e devolve 201 com o total correto" do
      usuario = Usuario.create!(email: "ana@exemplo.com", password: "12345678")

      post "/pedidos",
           params: { pedido: { total: 150 } },
           headers: { "Authorization" => "Bearer #{token_para(usuario)}" }

      expect(response).to have_http_status(:created)
      corpo = JSON.parse(response.body)
      expect(corpo["data"]["attributes"]["total"]).to eq("150.0")
    end

    it "devolve 422 quando o total é inválido" do
      usuario = Usuario.create!(email: "ana@exemplo.com", password: "12345678")

      post "/pedidos",
           params: { pedido: { total: -10 } },
           headers: { "Authorization" => "Bearer #{token_para(usuario)}" }

      expect(response).to have_http_status(:unprocessable_entity)
    end
  end
end

Um request spec faz uma chamada HTTP de verdade contra a aplicação de teste: passa pela rota declarada em routes.rb, pelo middleware, pela autenticação via header, pelo controller e pelo serializer — na mesma ordem que um cliente real veria em produção.

Por que request spec ganhou a preferência sobre controller spec

Um controller spec chama a action do controller diretamente, pulando roteamento e boa parte do middleware — um teste verde nele não garante que a rota realmente existe em routes.rb, nem que o header de autenticação funciona do jeito que um cliente de verdade vai mandar. Um request spec testa o contrato real que qualquer cliente da API enxerga, e é por isso que ele é a opção preferida hoje pra testar uma API Rails.

Exercício

Escreva um model spec pra Pedido, cobrindo a validação validates :total, numericality: { greater_than: 0 } vista na lição de models e migrations, sem usar nenhuma gem de matcher além do RSpec puro.

Quiz rápido

O que um model spec tipicamente verifica, como no exemplo de Produto?
Por que request spec é preferido a controller spec para testar uma API atualmente?