U_OK_2023’s blog

主に日々のプログラミング学習についてのアウトプットと備忘録

【エラー】NoMethodError: 【@userインスタンスが nil 】

引き続き、オリジナルアプリ実装していきます。

 

ユーザーモデル単体テスト実装 example、エクスペクテーションを記述 bundle exec rspec spec/models/user_spec.rb テストコードを実行してエラー発生

https://i.gyazo.com/7b4ae9f248437b6eaa4fb4a3a0369711.png

①何が問題でどうしたい

エラーを解決して正常系単体テストをクリアしたい

②現在(位置)

describe を 記述し、before と example を定義し、 単体テストを実行

③問題点

describe が存在しない

④仮説

エラーを調べた結果

Failure/Error: とは、テストが実行できなかった、
もしくは失敗したことを意味する接頭辞である

NoMethodError: とは、呼び出そうとしたメソッドが定義されていない、
メソッドが存在しない、
もしくはそのスコープに存在しないメソッドを呼び出そうとした。

NoMethodError: でエラーの根幹とされているのは、
undefined method `descride' for main:Object なので、
そこに describe が存在するか確かめに行く

⑤試したこと

よく見ると、 descride となっている

descride 'ユーザー新規登録' do
  context '新規登録できる場合' do
    it 'nicknameとpositionとaffiliationとpasswordとpassword_confirmationが存在すれば登録できる' do
      expect(@user).to be_valid
    end
  end

正しくは、describe であるため、正しいスペルに修正した

この修正により、NoMethodError: は解決された。

しかし、新たに NoMethodError:

https://i.gyazo.com/7631a9bfe05dd3c81c9658aa5f976103.png

今度は、undefined method `valid?' for nil:NilClass

ということで valid? を見に行くことにしようとしたが、

現在は「正常系」の単体テストなので、 valid? という記述はどこにもしていない・・・

しかし、下記の記述に何かあることは確かなので調べに行く

 

spec/models/user_spec.rb

expect(@user).to be_valid は構文的に間違いないことを確認した

次に、疑わしいのは 情報を受け取っている @user

なので、@user を定義している場所を確認

 

spec/models/user_spec.rb

@user = FactoryBot.build(:user) 構文的に記述に問題はないことを確認

次に疑わしいのは、参照しているモデル :user

:user 元のモデルを確認

 

spec/factories/users.rb

構文的に記述に問題がないことを確認

情報の受け渡しの確認は終わったので、

次は、@user が正しく生成されているかを確認

ターミナル でコンソールを開く

rails c

 

値が全て存在するかを確認

@user = FactoryBot.build(:user)

 

FactoryBotによって生成されるインスタンスが、
バリデーションでエラーにならないか確認

@user.valid?

 

結果 true を確認できた

 

Rspecにおける@user インスタンスは正常に生成されていることを確認できたため

次は、メソッドに渡される直前の@user の中身を確認してみる

spec/models/user_spec.rb

puts @user.inspect # ここで@userの中身をコンソールに出力
expect(@user).to be_valid

 

ターミナルで

bundle exec rspec spec/models/user_spec.rb でテストを実行

実行結果は nil でした

 

Rspecにおける@user のインスタンスは正しく生成されているが、 テスト実行時には 中身がないということを確認

テスト前に@user インスタンスを生成しているのは、

before なので、正しくbeforeブロックが動き、 次にdescribeブロックが動いているかを確認

before do
    puts 'Start of before block'
    @user = FactoryBot.build(:user)
    puts @user.errors.full_messages
    puts 'End of before block'
  end
end 

describe 'ユーザー新規登録' do
  puts 'Start of describe block'
  context '新規登録できる場合' do
    it 'nicknameとpositionとaffiliationとpasswordとpassword_confirmationが存在すれば登録できる' do
      puts 'Start of it block' 
      @user = FactoryBot.build(:user)
      expect(@user).to be_valid
      puts 'End of it block'
    end
    puts 'End of describe block'
  end

ターミナルで

bundle exec rspec spec/models/user_spec.rb でテストを実行

実行結果は

mac@yunoMacBook-Air hibitumo % bundle exec rspec spec/models/user_spec.rb
Start of describe block
End of describe block

ユーザー新規登録
  新規登録できる場合
Start of it block
    nicknameとpositionとaffiliationとpasswordとpassword_confirmationが存在すれば登録できる (FAILED - 1)
  新規登録できない場合

puts 'Start of before block' と puts 'End of before block' の出力も、

puts @user.errors.full_messages も出力されず、

beforeブロックをすっ飛ばして、
いきなり、Start of describe block から処理が始まっていることを確認

⑥結果

beforeブロックが動いていないことを確認

example に 直接 @user = FactoryBot.build(:user) を記述

it 'nicknameとpositionとaffiliationとpasswordとpassword_confirmationが存在すれば登録できる' do
      @user = FactoryBot.build(:user)
      expect(@user).to be_valid
    end

ターミナルで

bundle exec rspec spec/models/user_spec.rb でテストを実行

正常系モデル単体テストをクリアすることができた

 

原因:

何らかの原因でbeforeブロックが動かず、 その結果、@userインスタンスが生成されず、 エクスペクテーションに空の@user が渡されエラーとなった

 

解決方法:

example に 直接 @user = FactoryBot.build(:user) を記述

 

気付き:

なぜ、beforeブロックが動かなかったのかが気がかり

調べてみると、

RSpec のバージョンによって、before ブロックの動作が異なることがあります。最新のバージョンにアップグレードすることで問題が解決する場合があります。

ということで、ふと 関係ないかもしれないが、 AWSを導入する時、初期設定時に、rails のバージョンを カリキュラムに合わせ 「3.2.0」でインストールしたが、もしかしたら、 「7.0.0」だったのではないか?という懸念を今、抱いている