Ruby
Rails
RSpec

Rails4.0におけるstrong_parametersをどうテストするか。

More than 5 years have passed since last update.

5月1日にRails 4.0.0.rc1がでましたね。

その時点で3,4週間でリリース出来ると行ってるので今月末ぐらいにはRails 4.0.0がリリースされそうですね。

Rails4.0.0で一番の変更点はやっぱりstrong_parametersですね。

controllerのprivateメソッドでparamsをpermitすることになるんですが、このテストをどう書くべきなのかなと悩んでます。

正直まだまだ、僕のTDDレベルは低いので色々とツッコミまってます(お手柔らかに。。)。


1. 環境

Rails (4.0.0.rc1)

rspec (2.13.0)

rspec-rails (2.13.1)

factory_girl (4.2.0)

factory_girl_rails (4.2.1)


2. controller

例えば、name, admin_flgを持つusersにおいて、userのnameだけpermitする場合。controllerは下記のようになります。


app/controllers/users_controller.rb

class UsersController < ApplicationController

def create
user = User.new user_params
user.save
end

private
def user_params
params.require(:user).permit(:name)
end
end



3. テスト

さて、本題のテストなんですが、privateメソッドだから呼び出しもとのpublicメソッドのcreateを通してテストするべきなんでしょうか?

でも、userのカラムが増えてきた時に面倒ですよね?

ということで、privateメソッドでもuser_paramsに対してはテストを書きましょう。

FactoryGirlとRspecを使ってます。


spec/factories/user.rb

FactoryGirl.define do

factory :valid_user_params, class: User do |f|
f.name "bucato"
end

factory :evil_user_params, parent: :valid_user_params do |f|
f.admin_flg "1"
end
end



spec/controllers/users_controller_spec.rb

require 'spec_helper'

describe UsersController do
describe "user_paramsのテスト" do
before do
@expect_user_attr = FactoryGirl.attributes_for(:valid_user_params)
end

it "過不足がない場合 postした値とpermitされた値が一致すること。" do
user_attr = FactoryGirl.attributes_for(:valid_user_params)

post :create, { user: user_attr }
expect(controller.instance_eval{ user_params }).to eq ( @expect_user_attr.stringify_keys )
end

it "permitしてない項目をpostされてもpermitされないこと" do
user_attr = FactoryGirl.attributes_for(:evil_user_params)

post :create, { user: user_attr }
expect(controller.instance_eval{ user_params }).to eq ( @expect_user_attr.stringify_keys )
end
end
end


これで例えば、userにemailというカラムをたして、createで値を入れることが出来るようにした際にも、

テストはfactories/user.rbに一行たすだけでOKですね。


spec/factories/user.rb

FactoryGirl.define do

factory :valid_user_params, class: User do |f|
f.name "bucato"
f.email "info@example.jp"
end

factory :evil_user_params, parent: :valid_user_params do |f|
f.admin_flg "1"
end
end



はまったほどでも無いんですが、ポイント

@expect_user_attr = FactoryGirl.attributes_for(:valid_user_params)

は、Hashのkeyがシンボルなのに対して、

user_params

は、keyがstringでした、そのため、比較の際には

expect(controller.instance_eval{ user_params }).to eq ( @expect_user_attr.stringify_keys )

とstringify_keysする必要があります。

後はprivate methodなんで、user_params と直接呼べないので instance_evalで呼び出しましょう。

rspec-rails使ってcontrollerのテストしてるので、

controller

はそのまま使えますね。


4. 最後に

まだまだ、いい方法は模索中なので、

他に良い書き方あったら教えて下さい。