いつものように「これ、誰がつかうん?」という小ネタです。
たまーにRSpecでメソッドってちゃんと呼び出されてるよね?というテストを書くと思います。with
を使うと引数に狙った値が渡っているかを検証できますが、ブロック付きはどうするか調べたのでそのメモです。
先に言ってしまうと検証は「&手続きオブジェクト」の場合のみ出来ます。
前段階
検証に使うプログラムはDeck
クラスを利用します。これは何枚かのカードを持っていてシャッフルしたり偶数と奇数を分けてくれます。今回の検証はDeck#split_even_numbers
でEnumerable#partition
にブロックを渡していますが、それをRSpecでテストする方法です。
本来であればメソッドを呼び出した結果を検証すべきですので、メソッド呼び出しのみのテストはいいと言ってはいません。用法用量を守るのはお兄さんとのお約束だぞ
class Deck
def initialize(cards)
@cards = cards
end
def shuffle
@cards.shuffle
end
def split_even_numbers
@cards.partition { |card| card.even? }
end
def split_odd_numbers
@cards.partition(&:odd?)
end
end
RSpec
ブロックの検証
with
にブロックを指定すると{ |card| card.even? }
を受け取ることができるようです。&block
としているのでProc
クラスのオブジェクトになっています。
Proc
クラスのオブジェクトをつくって比較すればいいか!と思っていたのですが、メソッドに渡してるブロックとは異なるようでテストはうまくいきませんでした
describe Deck do
describe '#split_even_numbers' do
let(:deck) { Deck.new(cards) }
let(:cards) { [5, 4, 3, 2, 1] }
it do
expect(cards).to receive(:partition).with(no_args) do |&block|
# この検証はうまくいかない
expect(block).to eq(Proc.new{ |card| card.even? })
end
deck.split_even_numbers
end
end
end
&手続きオブジェクト
「&手続きオブジェクト」といっていますが検証したいProc
クラスのオブジェクトとテストでの期待値が同じオブジェクトであれば今回のやりたいことは実現することが出来ます。
:odd?.to_proc
は常に同じオブジェクトを返すので検証で利用して期待した結果を得ることが出来ます。
describe Deck do
describe '#split_odd_numbers' do
let(:deck) { Deck.new(cards) }
let(:cards) { [5, 4, 3, 2, 1] }
it do
expect(cards).to receive(:partition).with(no_args) do |&block|
expect(block).to eq(:odd?.to_proc)
end
deck.split_odd_numbers
end
end
end