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
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
endUm 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ê
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
endUm 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.