はじめに
今年ももう少しですね。
個人的にQiitaの下書きが上限いっぱい溜まってしまったので
少しづつアウトプットを心がけていこうと身が引き締まる思いです。
1日いちQiita(1日Qiitaを1記事アウトプットしてみようという試み) を今日から個人的に勝手にとりあえず今年いっぱい始めてみようかなと思います。
インプットは楽しいのですが、アウトプットはついつい後回しにしがちなのですが
少しづつ成長していきたいです。
この記事で書くこと
- rspecの
let
とlet!
の違いを次に同じ失敗をしないように残すという取り組み。
「そうだ、テスト書こう」
と思い至って早xx日。日々未来の自分やチームメイトのため、ひいてはエンドユーザのため(QA的な)にせっせとテストを書く毎日を送っています。楽しいです。
記事を書くにあたって1時間くらいハマってしまったテストケース(一部わかりやすいように変更してあります。)
describe 'update callback' do
context 'when user name will be changed,' do
let(:user) { create(:user, name: "隣の アルパカさん") }
let(:offer) { create(:offer, status: 'offered', user_id: user.id, user_name: user.name) }
it 'update user_name of processing offers.' do
# 古い情報を変数へ入れる
old_user_name = user.name
user.update(last_name: "隣の", first_name: "ねこさん") # 処理1
offer.reload
expect(offer.user_name).to eq "隣の ねこさん" # 処理2
end
end
end
テストしている処理としては、
(処理1)userオブジェクトの名前を変更( last_name
と first_name
を結合したものが name
になる)
- 処理1が実行されると
after_update callback
を利用して、そのユーザに紐付いた進行中の申込みを更新。
(処理2)申込みのユーザ名が、変更されたユーザ名と一致しているかどうかを確認。
なのですが、
Failure/Error: expect(offer.user_name).to eq "隣の ねこさん"
expected: "隣の ねこさん"
got: "隣の アルパカさん"
# な、なにがおきているのか、、、
letとlet!の違い
今回テストケースが失敗したのはなぜだったのか?
僕たちは「こう動いてほしい。こういう意味で書いている」という気持ちでコードを書きますが、
その気持と、書いてある内容は一致しているとは限りません。
「なぜ失敗している?」「なぜこう動かない?」というのはすべて「そうなるように書いている」からそうなるのです。だから今回も僕の書き方に問題があったのです。
そこで学んだ違いが以下のものです。
let
は、その定義された値がテストケースの中で使用されたときに初めて定義される。
let!
は、blockが定義された時に定義される。
この違いを知らずに自分は大分時間を使ってしまいました。
今回は
let!(:user) { create(:user, name: "隣の アルパカさん") }
こうしないといけなかったんですね。
この学びを糧にして、よりよいソフトウェアを作っていこうと思います。
参考
迷ったときに立ち返りたいBetter Specs
http://www.betterspecs.org/#let