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

頭の整理

JavaScript, Ruby, RSpec, Node.js, Rails TDDなどに興味があるWeb系SEが学んだことを整理していきます

RSpec Mocks 2.14で導入されたSpyとRSpec2.14の新記法について

RSpec 2.14 で新記法が導入されてRSpec Mocks 2.14でSpyが導入されていたので整理してみました.
stub()とshould_receive()の代わりにallow().to receive()とexpect().to receive()が使えるようになっていたり,Spyが導入されたことでRSpecを用いたテストの記述が柔軟になり,わかりやすく書けるようになりました.今までのRSpec Mocksで使ってきたMock ObjectとTest Spyの違いについても少し整理してみました.

Myron Marston » RSpec 2.14 is released!
このリリースノートのサンプルコードをいくつか引用して説明します.

Rspec Mocksのmessage expectationに新しい記法が追加されました.
mailer = double("Mailer")

# old syntax:
mailer.stub(:deliver_welcome_email)
mailer.should_receive(:deliver_welcome_email).with(an_instance_of(User))

# new syntax
allow(mailer).to receive(:deliver_welcome_email)
expect(mailer).to receive(:deliver_welcome_email).with(an_instance_of(User))

stub()の代わりにallow().to receive()が,should_receive()の代わりにexpect().to receive()が使えるようになりました.

RSpec MocksにSpyが追加されました.

※注意:下記のコードではUserCreationService.new()の中でdeliver_welcome_emailが呼び出されるという前提があるみたいです
Spyを使わない場合

mailer = double("Mailer")
expect(mailer).to receive(:deliver_welcome_email).with(an_instance_of(User))
UserCreationService.new(mailer).create_user(params)


Spyを使う場合

mailer = double("Mailer", deliver_welcome_email: nil)
UserCreationService.new(mailer).create_user(params)
expect(mailer).to have_received(:deliver_welcome_email).with(an_instance_of(User))

違いは,deliver_welcome_emailが実行された後にhave_receivedを使ってメソッド呼び出しや引数などを検査できるところです.
テストのセットアップ→テスト対象の動作の実行→結果の検査という流れが書きやすくなりました.

上記のリリースノートには,double().as_null_objectを使っても同じような書き方ができると書かれていました.

mailer = double("Mailer").as_null_object
UserCreationService.new(mailer).create_user(params)
expect(mailer).to have_received(:deliver_welcome_email).with(an_instance_of(User))
補足 Mock ObjectとTest Spyについて

Test Spyの説明は以下のエントリが参考になると思います.
xUnit Test PatternsのTest Doubleパターン(Mock、Stub、Fake、Dummy等の定義) - 千里霧中
特に下記の部分がわかりやすいと思います.

 なおMock ObjectとTest Spyは両方とも間接出力を検証するためのTest Doubleです。ただ「Mock ObjectはMock Object内で間接出力結果を評価する」のに対し、「Test Spyは間接出力を保持するだけで、間接出力結果の評価は後からテストコード上で行う」という違いがあります。

間接出力という言葉に関してはエントリ内で説明されています.
RSpec Mocksにおいてはテストコード上での評価は行えるので,Spyの機能を使う旨みは記述の順番を自然に書けるということかなと個人的には思いました.

参考ページ

RSpec MocksのSpyに関しては下記も参考になります.
Spies - RSpec Mocks - RSpec - Relish

RSpec 2.14での変更点は他にも何点かあります.
詳しくは冒頭にもあげた下記のリリースノートが参考になります.
Myron Marston » RSpec 2.14 is released!