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を書く方法しかないんだろうなーと思ってる.
もっといい書き方がありましたらぜひ教えて下さい.