RSpec の partial double とはなにか
RSpec には #and_call_original というメソッドがあり、これを使いたい場面があったのですが、使い方を間違えて次のようなエラーが発生しました。
xxx is a pure test double. `and_call_original` is only available on a partial double.このエラーを見て、pure test double と partial double の違いがあまりわかっていないと感じ、partial double について色々調べてみました。
Pure と Partial
Partial double を理解するには、対照的な概念である Pure test double と合わせて理解するのが良さそうです。
Pure test double
まず Pure test double ですが、これは double や instance_double などのメソッドを用いて作られたテストダブルを指します。
# 以下はどちらも pure test double を作る
double(Foo)
instance_double(Foo)その他にも spy や instance_spy、class_double、 object_double なども同じくです。RSpec でテストを書いていれば日常的に使っているメソッドではないでしょうか。
Partial double
一方の Partial double ですが、こちらはまず実際のオブジェクトがあり、それに対してテストダブルのような振る舞いができるように拡張したものです。 テストダブルのような振る舞い、というのは例えばメソッドの返り値をモックするようなことです。
例として Rails アプリケーション内に User モデルあり、これの find メソッドをモックしたいようなケースがある場合、次のように書けます。
dummy_user = double('dummy user')
allow(User).to receive(:find).and_return(dummy_user)そしてこのコードにおいて、User は Partial double です。
Partial double は名前の通り "部分的な" テストダブルであるため、明示的に allow でモックした find 以外は元の実装のままになります。
class HelloWorld
def self.hello
'Hello'
end
def self.world
'World'
end
end
RSpec.describe HelloWorld do
it do
allow(HelloWorld).to receive(:hello).and_return('GoodBye')
expect(HelloWorld.hello).to eq 'GoodBye' # 'GoodBye' を返すようにモックされている
expect(HelloWorld.world).to eq 'World' # world メソッドはそのまま
end
end上の例はクラスメソッドですが、インスタンスメソッドでも同様です。以下は、HelloWorldクラスのメソッドをすべてインスタンスメソッドに置き換えた例です。
class HelloWorld
def hello
'Hello'
end
def world
'World'
end
end
RSpec.describe HelloWorld do
it do
hello_world = HelloWorld.new
allow(hello_world).to receive(:hello).and_return('GoodBye')
expect(hello_world.hello).to eq 'GoodBye' # 'GoodBye' を返すようにモックされている
expect(hello_world.world).to eq 'World' # world メソッドはそのまま
end
endまとめ
まとめると、double や instance_double などのメソッドを使って明示的にテストダブルを作っている場合は Pure で、そうではない場合は Partial と判断できそうです。少し調べたのですが、Pure か Partial かを正確に判断できるメソッドなどは存在しないようでした。
and_call_original や and_wrap_original といったメソッドは、Partial test double の方しか使えません。メソッドの役割とテストダブルの違いを理解しておくと自然とそうなることがイメージしやすくなると思います。
参考URL

h3pei
フリーランスのソフトウェアエンジニア。Ruby / Rails アプリケーションの開発が得意領域。設計・実装・運用まで含めてプロダクト開発が好きです。
Questalという目標達成コミュニティサービスを開発しました。仲間と一緒に目標達成に取り組みたい方はぜひご利用ください。