change マッチャの挙動をきちんと理解していなくてつまづきました。
class User < ActiveRecord::Base
has_many :blogs
end
class Blog < ActiveRecord::Base
belongs_to :user
end
class UsersController < ApplicationController
def index
@user = User.new(name: 'popo')
@user.save
b = Blog.new(title: 'mudotaosenai', user_id: @user.id)
b.save
render nothing: true
end
end
といったソースがあるとして(かなり適当です、ごめんなさい) 最初は spec をこう書きました。
require 'rails_helper'
RSpec.describe UsersController, :type => :controller do
it 'assigins(:user)' do
get :index
expect(assigns(:user)).to eq User.last
end
it 'blogs.count' do
expect {
get :index
}.to change { assigns(:user).blogs.count }.by(1)
end
end
assigns(:user) は Green ですが blogs.count は Red です。
Failures:
1) UsersController blogs.count
Failure/Error: }.to change { assigns(:user).blogs.count }.from(0).to(1)
NoMethodError:
undefined method `blogs' for nil:NilClass
最初はなんで assings(:user) が nil になるのか分からなかったのですが、change メソッドはブロック内に記述した処理の実施前、実施後に値を取得しに行くことを理解し原因がはっきりしました。
このケースでは expect { get: index } とあるので、 get: index が実行される前に一度 @user の値を取得しようとしますが、ruby ではインスタンス変数は呼び出されて初めてセットされるので、get: index の実施前は @user は nil となります。
例があまり良くないですが、 change メソッドでは assigns は nil になるといったことでした。