🤖

allow_any_instance_ofを使うとRubocopに怒られる理由

2021/07/22に公開

自身が参加するプロジェクトでは、rubocopの縛りによりallow_any_instance_ofを使用すると警告が出てしまいます。

先延ばしが得意な私は、一旦allow_any_instance_ofで逃げといて後で書き換えよーみたいなことをしてしまっていて、結局あとで調べながら書き直すということを繰り返していました。

そのため改めて記事にすることで「一旦allow_any_instance_ofで逃げる」ということがなくなるかなと思い書いています。

allow_any_instance_ofの書き換え

# Avoid stubbing using `allow_any_instance_of`. (convention:RSpec/AnyInstance)
# allow_any_instance_ofの使用を回避してね。
before do
  allow_any_instance_of(Client).to receive(:get_email).and_return(email)
end

↓↓↓

before do
  client = instance_double(Client)
  allow(Client).to receive(:new).and_return(client)
  allow(client).to receive(:get_email).and_return(email)
end

なぜ警告が出るのか?

rspec-mocksのReadmeを見てみる

https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class

そもそもrspec-mocksは個々のオブジェクトやインスタンスのために設計されたものであるが、この機能はクラス全体に対して機能しちゃうため意味的に混乱を招くパターンがあると。

まとめると下記の3つの理由からだと解釈しました。

理由1. 一見すると下記のような2つの解釈ができてしまい混乱を招く

  • 各Widgetインスタンスがnameメソッドを2回受け取る(正解)
  • Widgetインスタンスは合計2回、nameメソッドを受けとる(間違い)
allow_any_instance_of(Widget).to receive(:name).twice

理由2. テストが多くのことをやろうとしているか、テスト対象のオブジェクトが複雑すぎる可能性あり

理由3. 歴史的に最も多くのバグが発生している

Discussion