Ruby on Railsを使い始めて2ヶ月の初心者がControllerのテストシナリオを書いたときにハマった悲しい事象の共有。
前提条件
- RailsはJSONを吐くWebAPI
- rails (5.1.6)
- rspec-core (3.7.1)
- factory_bot_rails (4.8.3)
テスト対象のController
よくあるControllerです。サンプルで :create
と :update
の2つだけ。本来は :index
:show
:destroy
もあります。
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
render json: @user
else
render json: {}
end
end
def update
@user = User.find_by(params[:id])
if @user
if @user.update(user_params)
render json: @user
else
render json: {}
end
else
render json: {}
end
end
private
def user_params
params.require(:users).permit(:name, :age)
end
end
作ってあるroutes.rb
シンプルに。
Rails.application.routes.draw do
resources :users
end
rails routes
した結果も一応
Prefix Verb URI Pattern Controller#Action
# 略
POST /users(.:format) users#create
PATCH /users/:id(.:format) users#update
# 略
書いたテストコード
require 'rails_helper'
describe UsersController, type: :controller do
# rails_helper内で
# config.include FactoryBot::Syntax::Methods
# を設定している前提
let(:user) { create(:user) }
describe 'Post #create' do
let(:param) do
{
users: {
name: 'Alice',
age: 21
}
}
end
context 'when send correct parameters' do
let(:http_response) do
post :create, params: param
end
it 'responds status "200 OK"' do
expect(http_response.status).to eq 200 # test OK
end
end
end
describe 'Patch #update' do
let(:param) do
{
users: {
id: users.id
name: 'Bob',
age: 30
}
}
end
context 'when send correct parameters' do
it 'responds status "200 OK"' do
expect(http_response.status).to eq 200 # test NG
end
end
end
end
んでテストNG時に表示されるエラーメッセージがこれ
ActionController::UrlGenerationError:
No route matches {:action=>"update", :controller=>"users", :users=>{:id=>2, :name=>"Bob", :age=>30}}
ルーティングがうまくできていない模様。
updateに必要なパラメーターはIDだけだし、ちゃんと渡してるのに…
解決策
上の状態だとルーティングが必要としているパラメーターが渡せていません。
URI Patternの :id
とは、Strong Parametersを通る前のパラメーターです。
# 略
describe 'Patch #update' do
let(:param) do
{
id: users.id, # これを追加
users: {
# id: users.id # これは削除
name: 'Bob',
age: 30
}
}
end
# 略
わかってしまえば簡単なのに、これで半日融かしました。
正確にやるなら、nameやageもidと同じくusersの外にも指定してあげるといいと思います。
ご自愛ください。