RSpecでモックを使って外部サービスに依存するコードのテストを書いてみた

こんな風にモックを使ってテストすればいいのかな.変な点があったら指摘して下さると嬉しいです.

目標

Twitterとは通信せずにTwitterクラスを使うコードのテストを行う(Twitterクラス関連のコードは適当にパスさせる)

sample_tweet.rb

  • SampleTweetのコンストラクタでTwitter::Baseクラスのインスタンス@twitterを作る
  • SampleTweet#hogeメソッドで@twitter.updateを呼び出し"hoge"という文字列をTwitterにpostする
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'

class SampleTweet
  def initialize(consumer_token_key, consumer_secret,
                 access_token_key, access_secret)
    # OAuthで認証する
    oauth = Twitter::OAuth.new(consumer_token_key, consumer_secret)
    oauth.authorize_from_access(access_token_key, access_secret)
    @twitter = Twitter::Base.new(oauth)
  end

  def hoge
    # Twitterに"hoge"とpostする
    @twitter.update("hoge")
  end
end

sample_tweet_spec.rb

  • SampleTweet#hogeを実行して例外が発生しないことを確認する程度のテストを行う
  • Twitterとは通信せずにSampleTweet#hogeのテストを行う(Twitterクラス関連のコードは適当にパスさせる)
  • Twitter::OAuthやTwitter::Baseのモック(偽物)を作り,各メソッドを偽装して何も処理しないようにする
  • Twitter::OAuthやTwitter::Baseのnewがモックのインスタンスを返すように偽装する

sample_tweet_spec.rb

require 'sample_tweet.rb'

describe SampleTweet do
  before(:all) do
    # Twitter::OAuthのモックを作り,メソッドを偽装する
    @oauth = mock(Twitter::OAuth)
    @oauth.stub!(:authorize_from_access).with(
      'dummy_access_token_key',
      'dummy_access_secret')

    # Twitter::OAuth.newがモックのインスタンスを返すようにする
    Twitter::OAuth.stub!(:new).with(
      'dummy_consumer_token_key',
      'dummy_consumer_secret'
      ).and_return(@oauth)

    # Twitter::Baseのモックを作り,メソッドを偽装する
    @twitter = mock(Twitter::Base)
    @twitter.stub!(:update)

    # Twitter::Base.newがモックのインスタンスを返すようにする
    Twitter::Base.stub!(:new).with(@oauth).and_return(@twitter)

    # SampleTweetクラスのインスタンスを作る
    @sample = SampleTweet.new(
      'dummy_consumer_token_key',
      'dummy_consumer_secret',
      'dummy_access_token_key',
      'dummy_access_secret')
  end

  # SampleTweet#hogeのテスト(Twitterにはpostされない)
  it 'should post "hoge" to twitter' do
    @sample.hoge
  end
end

これでTwitterにpostせずにTwitterクラスを使うコードをテストできる.

$ spec -cfs sample_tweet_spec.rb

SampleTweet
- should post "hoge" to twitter

Finished in 0.003382 seconds

1 example, 0 failures

newを書き換えてモックのインスタンスを返すようにする点がRubyらしくて面白いと思う.