LoginSignup
2

More than 5 years have passed since last update.

rspecのletで定義した変数をbeforeで変更するときの注意

Last updated at Posted at 2018-11-22

rspecのletで定義した変数をbeforeで変更しても、思ったようには行かないよという話です。

akiyah_spec.rb
# frozen_string_literal: true

require "rails_helper"

describe "Akiyah" do
  let(:int) { 123 }
  let(:str) { "abc" }
  let(:arr) { ["a", "b", "c"] }
  before do
    int = 456
    str = "def"
    arr[0] = "x"
    arr = ["d", "e", "f"]
    arr[1] = "y"
  end
  it { expect(int).to eq 123 }
  it { expect(str).to eq "abc" }
  it { expect(arr).to eq ["x", "b", "c"] }
end

letで宣言した変数をbefore内で=で代入しても、itの中では変わっていません。
beforeの中で(あとで使えない)新しい別の変数を作っているだけなんですね。

Array(やHash)の場合に、その中の要素を置き換えている場合は、itの中でも反映されます。

意外にこういう状況にはならないので、あんまり問題にはならないのですが、この前モブプロしているときに遭遇したので書いておきました。

コメントで解説していただいたので追記

letで定義しているのは変数ではなくてメソッドなのだと理解すれば、上のようなコードをみても誤解は減りそうです。
変数 みたいに見えるものを メソッド の呼び出しだとわかるように変えてみました。

akiyah_spec.rb
# frozen_string_literal: true

require "rails_helper"

describe "Akiyah" do
  let(:int) { 123 }
  let(:str) { "abc" }
  let(:arr) { ["a", "b", "c"] }
  before do
    int = 456
    str = "def"
    arr()[0] = "x"
    arr = ["d", "e", "f"]
    arr[1] = "y"
    p arr #=> ["d", "y", "f"]
  end
  it { expect(int()).to eq 123 }
  it { expect(str()).to eq "abc" }
  it { expect(arr()).to eq ["x", "b", "c"] }
end

beforeで arr()[0] = "x" をすると、 arr() の結果が変更されるのは面白いですね。コメントで書いていただいたように、letで定義したメソッドは戻り値を保存しておくからこうなるのですね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2