15 Jun 2012

ひとりごと on RSpec

ああ かれこれ1時間くらい CapybaraのRSpec上でActioveRecord::Baseなクラスの値がchangeしないパターンにはまってた。

こんな場合;
ユーザのパスワードリセッタを実装するときにone_time_tokenを発行してメールを送信する。メール中のtokenとデータベイスに保存されたtokenが一緒かチェック。同じだったら、パスワードを再設定する画面に進む。他にもセキュリティを守るための処理はあるけど基本的な処理はそんなかんじ。

Specはこんな感じ
  1. let(:user) { User.make } # => machinist/acive_record  
  2.   
  3.  it "user's token should be updated" do  
  4.   expect{ click_button 'メール送信' }.to change{ user.one_time_token }  
  5. end  
  6.   
  7. expect{ click_button 'メール送信'; user.reload }.to change{ user.one_time_token }  
  8. # => Got: one_time_token is still ""  


正しくはuser.reloadを追加しないといけない。
  1. it "user's token should be updated" do  
  2.   expect{ click_button 'メール送信'; user.reload }.to change{ user.one_time_token }  
  3. end  

changeの中は遅延評価されたuser を参照しているからRSpecの空間で故意にreloadしないと one_time_tokenがActiveRecord上では変わらない。普通の人はすぐ気づくのかなあ?