##はじめに
業務でRSpecでテストコードを書いています。
先日「あれ、通るはずのテストが通らない。。。(´・ω・`)」と思ったら「let!」の「!」を付け忘れていました。
備忘録として、letとlet!の違いをまとめておきます。
##let
letは、定義した定数が初めて使われたときに評価されます。
#composerが複数のsongを持つものとする
Rspec.describe Sample do
let(:composer) { create(:composer) }
let(:composer_song) { create(:song, composer: composer, title: 'きらきら星') }
it '〜〜' do
expect(composer).to ~~
end
end
end
ここでは、expect(composer).to
のcomposer
が出てきたタイミングで、letで定義したcomposer
がcreateされる、ということになります。遅延評価と言うそうです。
以下のコードでは、テストは失敗します。
#composerが複数のsongを持つものとする
Rspec.describe Sample do
let(:composer) { create(:composer) }
let(:composer_song) { create(:song, composer: composer, title: 'きらきら星') }
it 'composerがcomposer_songを持っていること' do
expect(composer.song.first.title).to eq 'きらきら星'
end
end
end
composer_song
はcreateされておらず、composer.song.first
は空になり、エラーになります。
##let!
let!は、各テストのブロック実行前に定義した定数を作ります。
letの遅延評価に対して事前評価とも言うそうです。
先程のテストを成功させるには、「!」を付けてあげれば良いのです。
#composerが複数のsongを持つものとする
Rspec.describe Sample do
let(:composer) { create(:composer) }
let!(:composer_song) { create(:song, composer: composer, title: 'きらきら星') }
it 'composerがcomposer_songを持っていること' do
expect(composer.song.first.title).to eq 'きらきら星'
end
end
end
before(:each) do
と同じように使えるのですね。
##まとめ
・letは、定義した定数が初めて出てきたときにcreateされる
・let!は、各ブロック実行前に定数をcreateする
なんとなく「遅延評価」という言葉は知っていたものの、実際にハマってみて改めてその意味を理解できた気がします。。
間違っている点等あればご指摘いただけますと幸いです。
###余談
letで定義してspecが落ちるのでデバック用でpp
を付けて定数を出力すると、当たり前なのですがテストは通ります。
こんな感じ
#composerが複数のsongを持つものとする
Rspec.describe Sample do
let(:composer) { create(:composer) }
let(:composer_song) { create(:song, composer: composer, title: 'きらきら星') }
it 'composerがcomposer_songを持っていること' do
pp composer_song
expect(composer.song.first.title).to eq 'きらきら星'
end
end
end
pp composer_song
のcomposer_song
って何者?→let(:composer_song)
に辿り着き、createされるというわけですね。