存根依赖对象

时间:2016-09-29 13:46:52

标签: class rspec

假设我们有一个与另一个对象具有垂直依赖关系的对象     

class Ship
  def initialize
    ...
  end

  def launch
    ShipLauncher.new(self, platform: platform)
  end
end


class ShipLauncher
  def initialize(ship, platform:)
  ...
  end
end

我们想测试一下:    

it do
  allow(ShipLauncher).to receive(:new)

  ship = Ship.new
  ship.launch

  expect(ShipLauncher).to have_received(:new).with(ship, platform: 'x')
end 

直到现在一切似乎都很好,但如果我们像这样更改ShipLauncher类

 class ShipLauncher
  def initialize(ship, platform_number:)
  ...
  end
end

测试将在不应该通过时传递,因为ShipLauncher类需要另一个参数。我做错了什么?我必须通过集成测试来测试它吗?如果ShipLauncher类隐藏了很大的复杂性,会发生什么?我必须存根所有依赖项?

1 个答案:

答案 0 :(得分:1)

有一个名为"partial doubles"的功能可用于检查此内容。

首先,您需要启用它:

RSpec.configure do |config|
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
end

然后按照以下方式编写您的规范:

describe Ship do
  it "launches a ship" do
    ship = Ship.new
    expect(ShipLauncher).to receive(:new).with(ship, platform: 'x')

    ship.launch
  end 
end

这将传递原始代码:

> rspec ship_spec.rb  
.

Finished in 0.00429 seconds (files took 0.19664 seconds to load)
1 example, 0 failures

现在,进行更改:

class ShipLauncher
  def initialize(ship, platform_number:)
    ...
  end
end

你会收到这个错误:

rspec ship_spec.rb  
F

Failures:

  1) Ship should receive new
     Failure/Error: expect(ShipLauncher).to receive(:new).with(ship, platform: 'x')
       Missing required keyword arguments: platform_number
     # ./ship_spec.rb:30:in `block (2 levels) in <top (required)>'

Finished in 0.00437 seconds (files took 0.2022 seconds to load)
1 example, 1 failure

请注意,规范是而不是实际调用initialize上的ShipLauncher方法,您可以验证:

class ShipLauncher
  def initialize(ship, platform_number:)
    raise Exception, "This code should not be run!"
  end
end

运行规范,在两种情况下都会得到相同的结果。部分double只是检查参数和方法名称是否与被模拟的对象匹配。