rspecのletの注意事項

rspecでletを使うとインスタンス変数を使わずにアクセスできるので便利です。

ただし、注意事項があります。

それは、遅延評価されるということです。

describe 'DELETE #destroy' do
  let(:contact) do
    create(:contact, firstname: 'Lawrence', lastname: 'Smith')
  end

  it "deletes the contact" do
    expect{
      delete :destroy, id: contact
    }.to change(Contact,:count).by(-1)
  end
end

上記のテストは失敗します。

原因は、expect{}より前にcontactが出てきていないので、contactを値がないからです。

呼び出されてから初めて作られるのですが、この場合は、その値がまだ存在していないです。

修正するとこうなります。

describe 'DELETE #destroy' do
  let(:contact) do
    create(:contact, firstname: 'Lawrence', lastname: 'Smith')
  end

  it "deletes the contact" do
    contact
    expect{
      delete :destroy, id: contact
    }.to change(Contact,:count).by(-1)
  end
end

これがダサいというのならば、let!を書くこともできます。

let! を使うと example の実行前に let! で定義した値が作られるようになります。

describe 'DELETE #destroy' do
  let!(:contact) do
    create(:contact, firstname: 'Lawrence', lastname: 'Smith')
  end

  it "deletes the contact" do
    contact
    expect{
      delete :destroy, id: contact
    }.to change(Contact,:count).by(-1)
  end
end

遅延評価されるというのが、ポイントです。