CucumberでMockに対するmethod呼び出しのexpectation(should_receive)をどのように書くか悩んでいる.
動くけど好きじゃない例
CucumberのexamplesにMockを使う例がある.
https://github.com/cucumber/cucumber/tree/master/examples/rspec_doubles
この例ではMockの作成とmethod呼び出しのexpectationの設定をGiven節に書いている.Then節には何も書いていない.
mocking.feature
Feature: Mocking In order to test external stuff I want to mock Scenario: Mock a transmogrifier Given I have a cardboard box When I poke it all is good
calvin_steps.rb
class CardboardBox def initialize(transmogrifier) @transmogrifier = transmogrifier end def poke @transmogrifier.transmogrify end end Given /^I have a cardboard box$/ do transmogrifier = double('transmogrifier') transmogrifier.should_receive(:transmogrify) @box = CardboardBox.new(transmogrifier) end When /^I poke it all is good$/ do @box.poke end
これでテスト自体は問題なく動くのだけど,いくつか不満点がある.
不満点
- "Given I have a cardboard box"で実行されるコードが"I have a cardbox"以上のことをやっている
- transmogrifierに関するGiven節を追加してコードを分割すればいいのかもしれないけど…
- method呼び出しのexpectationがGiven節に,methodの戻り値のassertionがThen節に分散してしまう
こんなふうに書きたい
method呼び出しのexpectationもmethodの戻り値のassertionもThen節に書きたい.
mocking.features
Feature: Mocking In order to test external stuff I want to mock Scenario: Mock a transmogrifier Given I have a cardboard box When I poke it Then all is ok
calvin_steps.rb
class CardboardBox def initialize(transmogrifier) @transmogrifier = transmogrifier end def poke @transmogrifier.transmogrify end end Given /^I have a cardboard box$/ do @transmogrifier = double('transmogrifier') @box = CardboardBox.new(transmogrifier) end When /^I poke it all is good$/ do @box.poke end Then /^all is ok/ do @transmogrifier.should_receive(:transmogrify) end
しかし,このテストは失敗する.Then節はWhen節よりもあとに実行されるため,When節で@box.pokeが呼ばれる時点で@transmogrifierにexpectationがセットされていないことが原因.
以上
どうすればこの手のテストがスマートに書けるのかまだよく分かってないけど,Then節がWhen節よりも後に実行される以上,Given節にexpectationを書く方法しかないんだろうなーと思ってる.
もっといい書き方がありましたらぜひ教えて下さい.