web-dev-qa-db-ja.com

rspec:コンストラクターによって呼び出されたインスタンスメソッドをスタブ化する方法は?

_class A
  def initialize
    @x = do_something
  end

  def do_something
    42
  end
end
_

元の実装が呼び出される前に、rspecで_do_something_をスタブするにはどうすればよいですか(したがって、42を_@x_に割り当てます)?もちろん、実装を変更することなく。

31
Pedro

これがrspecに機能を追加するコミットです -これは2008年5月25日でした。これであなたはすることができます

A.any_instance.stub(do_something: 23)

ただし、rspecの最新のgemバージョン(1.1.11、2008年10月)にはこのパッチが含まれていません。

このチケット は、メンテナンス上の理由でそれをヤンクアウトしたことを示しており、代替ソリューションはまだ提供されていません。

現時点ではできるようには見えません。 alias_methodなどを使用して手動でクラスをハックする必要があります。

22
Orion Edwards

私はこの解決策を http://pivotallabs.com/introducing-rr/ で見つけました

new_method = A.method(:new)

A.stub!(:new).and_return do |*args|
  a = new_method.call(*args)
  a.should_receive(:do_something).and_return(23)
  a
end
16
Denis Barushev

スペックのモックフレームワークでそれを行う方法はわかりませんが、mochaと簡単に交換して次のことを行うことができます。

# should probably be in spec/spec_helper.rb
Spec::Runner.configure do |config|
  config.mock_with :mocha
end

describe A, " when initialized" do
  it "should set x to 42" do
    A.new.x.should == 42
  end
end

describe A, " when do_something is mocked" do
  it "should set x to 23" do
    A.any_instance.expects(:do_something).returns(23)
    A.new.x.should == 23
  end
end
11
Dustin

または [〜#〜] rr [〜#〜]

stub.any_instance_of(A).do_something { 23 }
5
Chris Lloyd

今日のRSpecの最新バージョン-3.5では次のことができます:

allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
3
Lukasz Muzyka

私はデニス・バルシェフの答えが好きです。そして、new_method変数を不要にする外観上の変更を1つだけ提案したいと思います。 Rspecはスタブされたメソッドを操作するので、proxied_by_rspec__プレフィックスを付けてアクセスできます。


A.stub!(:new).and_return do |*args|
  a = A.proxied_by_rspec__new(*args)
  a.should_receive(:do_something).and_return(23)
  a
end
2
Serge Balyuk

RSpec2.6以降では使用できます

A.any_instance.stub(do_something: 23)

詳細については、 ドキュメント を参照してください。 (これが可能になったことを指摘してくれた rogerdpack に感謝します-私はそれ自体の答えに値すると思いました)

2
David Waller

インスタンスメソッドをスタブするには、次のようにします。

_before :each do
  @my_stub = stub("A")
  @my_stub.should_receive(:do_something).with(no_args()).and_return(42)
  @my_stub.should_receive(:do_something_else).with(any_args()).and_return(true)
  A.stub(:new).and_return(my_stub)
end
_

しかし、pschneiderが指摘したように、A.stub(:new).and_return(42)またはその効果をもたらす何かを使用してnewで42を返すだけです。

0
bluehavana

rspec_candy gemには、RSpec1とRSpec2の両方で機能するstub_any_instanceヘルパーメソッドが付属しています。

0
triskweline

これはあまりエレガントではないかもしれませんが、基本的には確実に機能するアイデアです。

テストするクラスを継承する小さなクラスを作成し、initializeメソッドをオーバーライドして、次のように、初期化でスタブを作成したsuperafterを呼び出します。

it "should call during_init in initialize" do
  class TestClass < TheClassToTest
    def initialize
      should_receive(:during_init)
      super
    end
  end
  TestClass.new
end

そして、あなたは行き​​ます!私はこれを私のテストの1つでうまく使用しました。

0
AdrienE