Rails

【Rubocop】RSpecのコード内でインスタンス変数を定義すると警告が出てしまう話

Rails

 

今回はRSpecのコード内でインスタンス変数を定義したことによるRubocop警告、その対処方法について解説したいと思います。beforeブロック内でインスタンス変数を定義し、そのインスタンス変数をそれぞれのテスト内で使用しているコードをよく見かけますが、それらはRubocop的にNGな方法ですので注意してください。

この記事の内容
  1. 概要
  2. 対処方法
  3. 注意点
  4. 参考

概要

RSpecのコード内でインスタンス変数をし、Rubocopの検証を実行することで以下のような警告が吐かれてしまいます。

'Avoid instance variables – use let, ' \
'a method call, or a local variable (if possible).'
インスタンス変数を用いず、代わりにletやメソッドの呼び出し、ローカル変数を使用してくださいと言われていますね。

対処方法

Rubocopのリファレンスを見てみると、対処例が記載されています。

悪い例ではbeforeブロック内でインスタンス変数を定義し利用しているのに対し、良い例ではインスタンス変数をletに置き換えていますね。

# 悪い例
describe MyClass do
  before { @foo = [] }
  it { expect(@foo).to be_empty }
end

# 良い例
describe MyClass do
  let(:foo) { [] }
  it { expect(foo).to be_empty }
end

 

このことを用いて、以下のコード(System Spec)でも書き換えを行なってみます。

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'Accountss', type: :system, js: true do
  before do
    @account = create(:account)
  end
  
  context 'Success' do
    it 'has a valid email and password' do
      login(@account)
      expect(page).to have_current_path authenticated_root_path, ignore_query: true
    end
  end
end
正しいメールアドレスとパスワードでログインした際は、authenticated_root_pathに飛ぶことを期待するテストになります。

 

これを書き換えると以下のようなコードになります。

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'Accounts', type: :system, js: true do
  context 'Success' do
    let(:account) { create(:account) }

    it 'has a valid email and password' do
      login(account)
      expect(page).to have_current_path authenticated_root_path, ignore_query: true
    end
  end
end

 

beforeブロック内で定義しているインスタンス変数をletに置き換えることでよりスッキリしたコードになりました。(もちろんRubocopの警告も出なくなります)

注意点

letは非常に便利なヘルパーメソッドですが、「遅延初期化」という実装する上で大きな注意点があります。

以下のようなコードはletの遅延初期化によってテストがパスしないため、このような場合はletではなくlet!を用いるようにしましょう。

let(:account) { Account.create(name: '田中太郎', loggable_type: '一般') }

it 'アカウント取得ができること' do
  expect(Account.first).to eq account
end

参考

 

 

今回はRSpecのコード内でインスタンス変数を定義したことによるRubocop警告、その対処方法について解説しました。よく書きがちなコードですが、今後気をつけていただけたらと思います。