こういう時にmockを使う
あるメソッドのテストコードを書きたい。
そのメソッドは内部で外部システムと通信をするclass(以下apiクラスと呼ぶ)を使っているため、実行のたびに結果が異なるのでテストがかけない。
apiクラスが返してくる値を決めてしまいたい。←コレをmockで解決する
前提コード
MyClass#some_infoをテストしたいが、ApiClass#some_dataがAを返すかBを返すかが状況で変わってくるのでテストできない。
class ApiClass def some_data() # 外部apiにアクセスしてデータを取ってくる(”A" or “B” を返す) end end class MyClass def initialize @api = ApiClass.new end def some_info data = @api.some_data case data when "A" return "aでした" when "B" return "bでした" end end end
ApiClassのmockを作ってテストする
describe 'moc練習' do before do @api_moc = double("ApiClass moc") # ApiClassのインスタンスのmocを作成 end context "ApiClass#some_dataがAを返す場合" do before do allow(@api_moc).to receive(:some_data).and_return("A") #@api_moc.some_data()が"A"を返すように設定 allow(ApiClass).to receive(:new).and_return(@api_moc) #ApiClass.newがapi_mocを返すように設定 end it '[aでした]が返る' do my_class = MyClass.new expect(my_class.some_info).to eq "aでした" end end context "ApiClass#some_dataがBを返す場合" do before do allow(@api_moc).to receive(:some_data).and_return("B") #@api_moc.some_data()が"B"を返すように設定 allow(ApiClass).to receive(:new).and_return(@api_moc) #ApiClass.newがapi_mocを返すように設定 end it '[bでした]が返る' do my_class = MyClass.new expect(my_class.some_info).to eq "bでした" end end end
他にも、、
expect(@api_moc).to receive(:some_data)
でsome_dataが呼び出されなければNGとしたり、
allow(@api_moc).to receive(:some_data).and_raise('エラーが発生しました’)
で例外を発生させたり、
呼び出し回数をチェックしたり、
引数をチェックしたりもできるらしい。
参考)