使用对象替身

object_double 可用于从现有的“模板”对象创建替身,并验证替身上的任何存根方法也存在于模板上。对于易于构建但可能产生深远副作用(例如与数据库或外部 API 通信)的对象,这很有用。在这种情况下,使用替身而不是真实对象可以让你专注于对象接口的通信模式,而不用担心意外导致副作用。object_double 还可用于验证使用 method_missing 定义的对象上的方法,而这在 instance_double 中是不可能的。

此外,object_double 可以与特定的常量值一起使用,如下所示。这适用于利基情况,例如处理单例对象时。

对现有对象进行替身

给定一个名为“spec/user_spec.rb”的文件,其中包含

class User
  # Don't want to accidentally trigger this!
  def save; sleep 100; end
end

def save_user(user)
  "saved!" if user.save
end

RSpec.describe '#save_user' do
  it 'renders message on success' do
    user = object_double(User.new, :save => true)
    expect(save_user(user)).to eq("saved!")
  end
end

我运行 rspec spec/user_spec.rb

那么示例应该全部通过。

对常量对象进行替身

给定一个名为“spec/email_spec.rb”的文件,其中包含

require 'logger'

module MyApp
  LOGGER = Logger.new("myapp")
end

class Email
  def self.send_to(recipient)
    MyApp::LOGGER.info("Sent to #{recipient}")
    # other emailing logic
  end
end

RSpec.describe Email do
  it 'logs a message when sending' do
    logger = object_double("MyApp::LOGGER", :info => nil).as_stubbed_const
    Email.send_to('hello@foo.com')
    expect(logger).to have_received(:info).with("Sent to hello@foo.com")
  end
end

我运行 rspec spec/email_spec.rb

那么示例应该全部通过。