19

ここでは、M HartlのRuby on Railsチュートリアルのコードの一部です。なぜインスタンス変数(@user)が必要なのか、どうしてなぜローカル変数を使わないのか説明できますか?また、インスタンス変数はクラスのインスタンス内の変数であると仮定されているため、どのクラスが@userからインスタンス化されていますか?rspecのインスタンス変数はどのように機能しますか?

require 'spec_helper' 

describe User do 

    before { @user = User.new(name: "Example User", email: "[email protected]") } 

    subject { @user } 

    it { should respond_to(:name) } 
    it { should respond_to(:email) } 
end 

答えて

32

そのインスタンス内のローカル変数の使用は、その範囲がbeforeに制限し、したがってエラーをもたらすであろうことを意味します。 @userはUser型ですが、describeブロックのインスタンス変数です。 Rspecには実行時にそれぞれdescribeブロックからクラスを作るいくつかの魔法があります。各例(itブロック)は、前記クラスのサブクラスとなる。クラスの継承により、例には@userが表示されます。

編集2017年5月14日

リンクされたブログ記事が使用できなくなりました。ウェイバックマシンリンクでの更新+関連セクションのインライン展開。

これは、blog postに詳述されているようなアンチパターンとみなされることに注意してください。代わりにletを使用してください。

letは、以下の利点を有する:

  • 例横切る 一例では複数回使用ではなく、場合にはメモ化されています。
  • これは遅延ロードされているため、変数を参照していない例の変数を初期化する時間を無駄にすることはありません。
  • 変数名に誤字があると例外が発生します。
+1

ああ、私は今それを得ると思います。私はいつも、ブロックが人間にはより読みやすく、他には何も読まないようにするためにブロックが使われたと考えていました。ありがとう:) – TradeRaider

+0

そのブログ記事はもはや利用できません。インスタンス変数の使用が反パターンであり、壊れたリンクを削除する理由を含めるために、回答を更新する価値があります。 – keoghpe

2

subject ad itブロックのスコープが異なるため、ローカル変数が機能しません。 @userは、RSpecによって生成されたクラスに属します。

12

ローカル変数はローカルメソッドのスコープ内にのみ存在するため、ローカル変数を使用することはできません。 before,subjectおよびitは、同じクラス内で異なるスコープを生成します。

before { user = User.new(name: "Example User", email: "[email protected]") } 

はあなたが

subject { user } 

インスタンス@userでそれを呼び出す未定義の変数を発生させます次のコードは、User(後にすべてのクラスのインスタンスである、あなたはUser.newとそれを作成します)。

ただし、インスタンス変数の代わりにletコマンドを使用すると便利です。また、定義する場合

subject { User.new(name: "Example User", email: "[email protected]") } 

beforeの使用は必要ありません。インスタンスにアクセスするためにsubjectメソッドを使用できるようにする特別なメリットもあります。これは、let(:subject)と同じです。

+4

'let'を使用して+1した場合:let(:user){User.create(name: "Example User"、email: "[email protected]")} ' – Meltemi

+0

件名を使用して+1します。新しい(名前: "Example User"、電子メール: "[email protected]")} –

関連する問題