web-dev-qa-db-ja.com

rspecのインスタンス変数はどのように機能しますか?

これはMHartlのRuby on Railsチュートリアルからのコードです。インスタンス変数(@user)が必要な理由と、ローカル変数。また、インスタンス変数はクラスのインスタンス内の変数であると想定されているため、@ userはどのクラスからインスタンス化されますか?

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
19
TradeRaider

そのインスタンスでローカル変数を使用すると、そのスコープがbeforeに制限されるため、エラーが発生します。 @userはUser型ですが、describeブロックのインスタンス変数です。 Rspecには、実行時に各describeブロックからクラスを作成する魔法があります。各例(itブロック)は、最終的にそのクラスのサブクラスになります。クラス継承により、例で@user

2017年5月14日編集

リンクされたブログ投稿は利用できなくなりました。 WaybackMachineリンクで更新+関連するセクションをここにインライン化します。

この ブログ投稿 で詳しく説明されているように、これはアンチパターンと見なされることに注意してください。代わりにletを使用してください。

letには次の利点があります。

  • 1つの例で複数回使用された場合はメモ化されますが、例間では使用されません。
  • 遅延読み込みされるため、変数を参照しない例で変数を初期化する時間を無駄にすることはありません。
  • 変数名にタイプミスがある場合、例外が発生します。
32
peakxu

ローカル変数はローカルメソッドのスコープ内にのみ存在するため、ローカル変数を使用することはできません。 beforesubject、および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の使用は必要ありません。また、let(:subject)を定義するのと同じように、インスタンスにアクセスするためにsubjectメソッドを使用できるという追加の利点も得られます。

12
Simone Carletti

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

2
Victor Deryagin