すごいぞRSpec(letとlet!編)

すでに前回のすごいぞRSpec(shared example group編) - ぷろぐらまねがで登場してるけどあらためてletを調べるよ。rspec-core(2.5.1)/features/helper_methods/let.featureを参考に。

let

要するにメモ化するわけで、同一サンプル内だと同じオブジェクトを使いまわせるのだな。違うサンプルでは改めて評価される。さらに遅延評価なので実際に評価されるのは最初にメソッドが呼ばれたときだ。

$count = 0

describe 'let' do
  let(:count) { $count += 1 }

  it 'memoizes the value' do
    count.should == 1
    count.should == 1
  end

  it 'is not cached across examples' do
    count.should == 2
  end
end
% rspec -cfs let_1.rb

let
  memoizes the value
  is not cached across examples

Finished in 0.00127 seconds
2 examples, 0 failures

let!

letとの違いは評価のタイミング。letが遅延評価なのに対してlet!はbefore each的に各サンプルの実行前に評価される。

$count = 0

describe 'let!' do
  invocation_order = []

  let!(:count) do
    invocation_order << :let!
    $count += 1
  end

  it 'calls the helper method in a before hook' do
    invocation_order << :example
    invocation_order.should == [:let!, :example]
    count.should == 1
  end
end
% rspec -cfs let_2.rb

let!
  calls the helper method in a before hook

Finished in 0.00056 seconds
1 example, 0 failures

じゃあlet!とbeforeってどんな順番なのか?

気になったのでやってみた。

$count = 0

describe 'let!' do
  invocation_order = []

  before(:each) { invocation_order << :before1 }

  let!(:count) do
    invocation_order << :let!
    $count += 1
  end

  before(:each) { invocation_order << :before2 }

  it 'calls the helper method in a before hook in described order' do
    invocation_order << :example
    invocation_order.should == [:before1, :let!, :before2, :example]
    count.should == 1
  end
end
% rspec -cfs let_3.rb

let!
  calls the helper method in a before hook in described order

Finished in 0.00062 seconds
1 example, 0 failures

ということでbeforeと同じタイミングで上から順番に評価されるっぽい。


letを単体で使うのはあまり効果ないような気がするけどどうだろうか?shared example groupやmockと組み合わせるのが主になるのかな。


続く