zakihayaメモ

RubyとRailsのことが中心

RSpec::Mocksが少しだけわかったので、忘れないようにまとめておく

用語

テストダブル テストコードの中で別のオブジェクトの代役を務めるオブジェクト
メソッドスタブ レスポンスを自由に定義できるメソッド
メッセージエクスペクテーション コールされることが保証されるメソッドスタブ

テスト対象コード

class Statement
  def initialize(customer)
    @customer = customer
  end
  
  def generate
    "Statement for #{@customer.name}"
  end
end

RSpec Book P.180より引用

メソッドスタブ

テストコード
describe Statement do
  it "uses the customer's name in the header" do
    customer = double('customer')                          ・・・①
    customer.stub(:name).and_return('Aslak')               ・・・②
    statement = Statement.new(customer)                    ・・・③
    statement.generate.should =~ /~Statement for Aslak/    ・・・④
  end
end

RSpec Book P.179より引用

① テストダブルを作成←こいつがCustomerクラスのインスタンス
  代わりをする
② ①で作成したテストダブルにメソッドスタブを追加
  →コールすると'Aslak'が返ってくるようなnameメソッドを
   customerに追加するイメージ
   customer.name
   =>'Aslak'
   となる
③ 作成したテストダブルを使ってStatementクラスのインスタンスを作成
④ statement.generateを呼ぶと、内部でテストダブルのcustomer.nameが
  呼ばれて結果が正しく表示されることを確認する

メソッドスタブを使うメリット
  • 上のコードでいうCustomerのようなクラスを作っていなくてもテストが書ける
  • StatementクラスのテストがCustomerの実装に依存しなくなる

メッセージエクスペクテーション

テストコード
describe Statement do
  it "uses the customer's name in the header" do
    customer = double('customer')
    customer.should_receive(:name).and_return('Aslak')  ・・・この行が変わってる
    statement = Statement.new(customer)
    statement.generate.should =~ /~Statement for Aslak/
  end
end

RSpec Book P.181より引用

メソッドスタブとの違い

customer.nameがコールされないとテストが失敗する

class Statement
  def initialize(customer)
    @customer = customer
  end
  
  def generate
    "Statement for Aslak"
  end
end

となっている場合に、
メソッドスタブ:成功
メッセージエクスペクテーション:失敗