如何期望对新创建的测试double进行方法调用?

时间:2012-06-17 07:53:32

标签: ruby rspec

说我有这样的代码:

class Car
  def test_drive!; end
end

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

现在,使用RSpec我想测试/ spec 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

1 个答案:

答案 0 :(得分: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