Tech Racho エンジニアの「?」を「!」に。
  • 開発

rspecで継承したクラスにany_instance.stubを使うとSystemStackError (stack level too deep) になる

タイトルのままですが、rspecで

User.any_instance.stub(:enabled?) { true }

のような処理をする際、SystemStackError stack level too deepが発生することがあります。

これは、継承の親クラスに対してany_instance指定し、実際には子クラスのメソッドが呼び出された場合に発生します。
仕様のようです。
https://github.com/rspec/rspec-mocks/issues/94

この辺りで無限ループしていますね。

# gems/rspec-mocks-2.10.1/lib/rspec/mocks/any_instance/recorder.rb:173
def observe!(method_name)
  stop_observing!(method_name) if already_observing?(method_name)
  @observed_methods << method_name
  backup_method!(method_name)
  @klass.class_eval(<<-EOM, __FILE__, __LINE__)
    def #{method_name}(*args, &blk)
      self.class.__recorder.playback!(self, :#{method_name}) # ここ
      self.__send__(:#{method_name}, *args, &blk)
    end
  EOM
end

特に、単一テーブル継承(UserのサブクラスMemberとAdminを作るなど)を使った場合に、うっかりやりがちです。
解決策としては、子クラス(MemberやAdmin)に直接any_instance指定すればOKです。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。