スタブとして定数を返すのではなく、そのとき渡された引数に応じて独自に別メソッドを実装して戻り値を返したい場合にどうするか。
例えば、金額を受け取って返金額を返すrefund!
というメソッドがあったとする。
# 呼び出し例
payment.refund!(10000)
このrefund!
をテスト内でスタブ化したい場合、通常であれば下記のような実装が考えられる。
let(:refund_price) { 2000 }
before do
allow_any_instance_of(Payment).to receive(refund!).and_return(refund_price)
end
しかし、テストごとにrefund!が違う引数で呼ばれる場合、その都度let
でrefund_price
を定義する必要があり大変面倒になる。
そこでrefund!
の中身を独自のシンプル実装で代替したい場合には、receive
メソッドにブロックを渡してやることで実現できるようだ。
allow_any_instance_of(Payment).to receive(refund!) {|_, param| param*0.2 }
ブロック引数の第一引数がレシーバ自体のインスタンス(この場合はPayment
のインスタンス)、第二引数以降がrefund!
に渡される引数らしい。
上のように書くと、例えば
ret1 = payment.refund!(10000)
ret2 = payment.refund!(20000)
という処理について、ret1
には2000
、ret2
には4000
が格納されるようにシミュレートできる。