Overview
この記事ではクラスメソッドとインスタンスメソッドを、テスト対象に都合の良いデータを返してくれるように mock 化する方法
を紹介します。
自動テスト界隈では「本物のふりをしてくれるオブジェクト」をまとめてテストダブルと言い、テスト対象からの出力を受けるのが mock で、テスト対象に都合の良いデータを返してくれるのが stub と言いうのでは?という方がいらっしゃるかと思いますが、この記事ではこれらの用語の定義はややこしいので触れません... テストを pass するためにテスト中に都合の良いデータを返す方法という観点だけでお読みください
テスト中のクラスメソッドの返り値を固定する
では、まずはクラスメソッドからです。
こういうクラスがあったとします。
class ExampleClass
def self.real_method # クラスメソッドは self で定義
'real'
end
end
この real_method
の返り値を、テスト中に dummy
にしたい場合はこのように書きます。
require 'spec_helper'
describe 'ExampleClass' do
it 'return dummy'
allow(Example).to receive(:real_method).and_return('dummy')
puts Example.real_method # dummy
end
end
テスト中のインスタンスメソッドの返り値を固定する
続いてインスタンスメソッドです。
こういうクラスがあったとします。
class ExampleClass
def real_method # インスタンスメソッドは self いらない
'real'
end
end
テストはこう書きます。
require 'spec_helper'
describe 'ExampleSlass' do
it 'return dummy' do
allow_any_instance_of(Example).to receive(:real_method).and_return('dummy')
puts Example.new.real_method # dummy
end
end
allow_any_instance_of
を使うところがキモですね。
ちなみに、インスタンスメソッドをただの allow で mock しようとすると以下のように Example に real_method というクラスメソッドはないよというエラーを吐かれ、
allow(Example).to receive(:real_method).and_return('dummy')
# Example does not implement: real_method
テスト中に new してインスタンスを mock しようとすると、テストで new したインスタンスと実際のコードで new したインスタンスは異なるので mock ができず、real
が返されます。
allow(Example.new).to receive(:real_method).and_return('dummy')
# ここで new しても、実際のコードは別のインスタンスなので real が返される
まとめ
- クラスメソッド
allow(Class).to receive(:target_method).and_return('mock_value')
- インスタンスメソッド
allow_any_instance_of(Class).to receive(:target_method).and_return('mock_value')