概要
app/controllers/hidamari_controller.rb
class HidamariController < ApplicationController
# POST /hidamari/sketch
def sketch
### 略 ###
open('http://www.tbs.co.jp/anime/hidamari/')
### 略 ###
end
end
上記のように open-uri の Kernel.open を使用しているコードがあります。
その単体テストで open が呼ばれることを確認したいです。
うーん、Kernel.open をスタブする方法がぱっと思い浮かばなかったので色々試してみました。
spec/controllers/hidamari_controller_spec.rb
# NG
expect(Kernel).to receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
# OK
expect_any_instance_of(Kernel).to \
receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
# OK
expect_any_instance_of(Object).to \
receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
# NG
expect_any_instance_of(BasicObject).to \
receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
# OK (better)
#
# described_class == HidamariController #=> true
expect_any_instance_of(described_class).to \
receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
# OK (best) ※ @jnchito さんにコメントで教えて頂きました。
#
# controller は RSpec::Rails::ControllerExampleGroup に用意されている変数で、
# テスト対象のコントローラーのインスタンスが格納されています。
#
# controller.is_a?(HidamariController) #=> true
expect(controller).to \
receive(:open).with('http://www.tbs.co.jp/anime/hidamari/')
post(:sketch)
controller
をスタブする方法がもっともスマートだと思います。
expect_any_instance_of
を使わずに expect
で書ける (余計なスタブを行わずに済む) からです。