1

次のようなコードがあるとします。

class Car
  def test_drive!; end
end

class AssemblyLine
  def produce!
    car = Car.new
    car.test_drive!
  end
end

今、RSpec を使用して、私はテスト/スペックAssemblyLineも実行せずに行いたいと考えてCarいます。Ruby では依存性注入を行わないと聞きましたが、new代わりにスタブを使用しています。

describe AssemblyLine
  before do
    Car.stub(:new).and_return(double('Car'))
  end

  describe '#produce'
    it 'test-drives new cars' do
      the_new_instance_of_car.should_receive(:test_drive) # ???
      AssemblyLine.new.produce!
    end
  end
end

ご覧のとおり、問題は にありthe_new_instance_of_carます。produceが呼び出される前はまだ存在せず、produce返された後では、メソッド呼び出しの期待値を設定するには遅すぎます。

スタブ化されたメソッドでコールバックを使用する回避策を考えることができますが、newそれはかなり厄介です。この一見一般的な問題を解決するには、よりエレガントで慣用的な方法が必要です。右...?


更新:これが私がそれを解決した方法です。

describe AssemblyLine
  def stub_new_car(&block)
    Car.stub(:new) do
      car = double('Car')
      block.call(car) if block
      car
    end
  end

  before { stub_new_car } # to make other tests use the stub as well

  describe '#produce'
    it 'test-drives new cars' do
      stub_new_car { |car| car.should_receive(:test_drive) }
      AssemblyLine.new.produce!
    end
  end
end
4

1 に答える 1

1

テスト ダブルに期待値を設定できます。

describe AssemblyLine do
  let(:car) { double('Car') }
  before { Car.stub(:new) { car } }

  describe "#produce" do
    it "test-drives new cars" do
      car.should_receive(:test_drive!)
      AssemblyLine.new.produce!
    end
  end
end

クラスを呼び出すこともできますany_instance(RSpec 2.7 以降だと思います):

describe AssemblyLine do
  describe "#produce" do
    it "test-drives new cars" do
      Car.any_instance.should_receive(:test_drive!)
      AssemblyLine.new.produce!
    end
  end
end
于 2012-06-17T08:20:32.233 に答える