読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

Rspecでスタブを使ったときのメモ

こんなコードがあったんです。
メールアドレス変更をするときに、ユーザーIDと新メールアドレスとトークンを持つモデルのテストで、トークンがかぶったらマズイからbefore_saveでunique_tokenという、渡されたトークンが既に存在しないか確認するメソッドを呼ぶという。

  attr_accessible :email
  before_save do |email_change|
    email_change.token = EmailChange.unique_token(SecureRandom.urlsafe_base64)
  end

  def self.unique_token(token)
    if EmailChange.where(token: token).count > 0
      EmailChange.unique_token(SecureRandom.urlsafe_base64)
    else
      token
    end
  end

このunique_tokenのテストを書くときの問題として、トークンかぶりのテストをするときは、任意のトークンをDBに入れておくしかないんだけど、もともとランダムな値を返すメソッドをbefore_saveで呼んでいるので、ふつうにやるとそれができないという点。

こんなときにはスタブを使う。こんな感じに書いてみた。

  describe "unique_token" do
    context "the token has already been taken" do
      before do
        EmailChange.stub(:unique_token).and_return('token')
        @email_change.save
        EmailChange.unstub!(:unique_token)
      end

      it { expect(EmailChange.unique_token('token')).not_to eq('token') }
    end

    context "the token has NOT already been taken" do
      before do
        @email_change.save
      end

      it { expect(EmailChange.unique_token('token')).to eq('token') }
    end
  end

いちど任意のトークンを保存したあとは、通常通りunique_tokenが動いてくれないと困るのでEmailChange.unstub!(:unique_token)しておいた。

便利やなぁ。