# 遅延評価の素晴らしさ
– 素晴らしいという話は他にもたくさん紹介されているので、そちらをご参照あれ。
# おそろしや(自分がハマった3つの罠)
① 書き方には要注意
let (:hoge) {...}
では働かない
let(:hoge) {...}
と、スペースを入れないようにしよう。私はこれで恥ずかしながら半日潰した。^^;;
② 呼ばれないと評価自体されない
たとえば、コントローラーのメソッドhoge_spec
は「すべてのUserオブジェクトのうち、その属性xyz
に99
が入っているものは除外して、インスタンス変数@users
に代入する」という仕様であった場合、
1 2 3 4 5 6 7 8 9 10 11 12 |
describe "hoge-spec" do let(:user1) { User.create(xyz: 99) } context "属性`xyz`に99が入っているものは" do before do @user2 = User.create(xyz: 0) end it "表示しない" do expect(assigns(:users)).to eq([@user2]) end end end |
さて、上記のテストコード、おやっ?と思った人はかなり戦ってきた人である。
これは、このテストコード自体に問題がある。たとえコントローラーのhoge_spec
で、Userオブジェクトの属性xyz
が9999
のものを外すコードを書いてしまっても、このテストコードでは見事パスしてしまうのだ!これは問題だ。テストにならん。
種明かしは後ほど。
③ exampleの中では最後のもののみが有効
遅延評価なので、次のような書き方ができるときっと楽しい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
describe "バリデーションチェック" do let(:params) {{name: name}} let(:name) {"花咲じいさん"} subject { User.new(params) } # モデルできちんとバリデーションチェックを行っているかどうかのテスト context "名前が nil,もしくはブランクなら" do let(:name) { nil } it { expect( subject.valid? ).to be_falsey } let(:name) { "" } it { expect( subject.valid? ).to be_falsey } let(:name) { "花咲婆さん" } it { expect( subject.valid? ).to be_truthy } end end |
こう書けたら、さぞかし楽だろう。しかし、そうは問屋がおろさなかった。この場合、モデルにきちんと
1 |
validates :name, presence: true |
としておいても、上の2つが、falseではなく、trueだと言われてエラーになってしまう。
そうなのだ。
最後にセットされた”花咲婆さん”がこのexample内で有効になっているためである。
なので、仕方がないからそれぞれcontext
で分けなければならない。
1 2 3 4 5 6 7 8 9 10 11 |
context "名前が nilなら" do let(:name) { nil } it { expect( subject.valid? ).to be_falsey } end context "名前が ブランクなら" do let(:name) { "" } it { expect( subject.valid? ).to be_falsey } end context "名前に「花咲じいさん」が入っているなら" do it { expect( subject.valid? ).to be_truthy } # 元々のものを利用 end |
となる。
さてさて、最後に②の種明かし…
をするはずだったが、わからなかった御仁はどうか自分でやってみてほしい。
これは、決して、いじわるじゃないぞ。