6

ですから、非常に単純化された、次のようなコードがあります。

class B
  def initialize opts
    @opts = opts
  end
end

class A
  def initialize opts
    # defaults etc applied to opts
    @b = B.new opts
  end
end

つまり、Aをオプションで初期化すると、Bが作成され、変更されたオプションのセットが渡されます。

B.newが正しい引数を取得することをテストしたいと思います。現在、RSpec / RRを使用して、次のように実行しています。

@b = Object.new
# stub methods on @b here
stub(B).new { |options|
  options[:foo].should == 'whatever'
  @b
}
A.new({:foo => 'whatever'})

しかし、これには2つの問題があります。

Bまず、実際のオプションを使用しての実際のコピーをインスタンス化することはできません。ブロック内でB.newを呼び出すと、スタブバージョンが呼び出され、スタックがポップするまでループします。スタブの前に設定することはでき@b = B.newますが、テストのポイントを破って、渡されるオプションがまだわかりません。

(そして誰かが私にそれを呼びかける前に:はい、厳密な単体テストの教義では、AのテストはBのすべてのメソッドをスタブ化する必要があり、多くをスタブ化する必要があるということは、そもそもコードが悪いことを意味します。)

第二に、後で別のブロックに入れるのshouldではなく、テストのセットアップに入れるのは間違っていると感じます。it ... do ... endしかし、実際のB(上記を参照)を作成できないため、構築後の状態を実際に調べることもできません。

何か案は?

4

3 に答える 3

3

のようなものを書くことができますB.should_receive(:new).with({:foo => 'whatever'})

個人的には、スタブやモッキングを避け、動作をテストしたいと考えています。指定された一連のオプションでnew が作成されるという事実は、B実装に依存するため、直接テストしません。

于 2012-07-06T05:19:23.810 に答える
1

Marc-Andreの回答のRRバージョン:

before do
  stub(B).new { @b }
end

it 'uses the correct options' do
  B.should have_received.new(hash_including(:foo => 'whatever'))
end
于 2012-07-06T05:58:12.390 に答える