expect_any_instance_of带有一个对象参数

时间:2016-02-22 08:29:04

标签: ruby rspec

我正在测试一个类的初始化块,如下所示

class A
  attr_accessor :client

  def initialize(options, configuration)
    self.client = B.new(options)
    config = C.new(
      url: configuration[:url],
      headers: configuration[:headers],
      username: configuration[:username],
      password: configuration[:password]
    )
    client.configure(config)
  end
end

class C
  def initialize(options)
    # does something with options hash
  end
end

class B
  def initialize(options)
    # does something with options hash
  end

  def configure(config)
    # some configuration with config object
  end
end

我的测试用例如下:

let(:options) {
  {
    force_basic_auth: true
  }
}

let(:configuration) {
  {
    url: 'https://localhost:3000',
    headers: { awesome: true },
    username: 'test',
    password: 'pass'
  }
}

let(:api_config) {
  C.new(configuration)
}

it 'configures object with passed params' do
  expect_any_instance_of(B).to receive(:configure)
    .with(api_config)

  A.new(
    options,
    configuration
  )
end

这使我的测试用例失败,因为在初始化块中创建的对象与我在期望中使用的api_config的object_id具有不同的object_id

   -[#<C:0x00000002b51128 @url="https://localhost:3000", @headers={:awesome=>true}, @username="test", @password="pass">]
   +[#<C:0x00000002a1b628 @url="https://localhost:3000", @headers={:awesome=>true}, @username="test", @password="pass">]

看到失败我在想是否是在初始化块中直接传递这些对象的最佳做法。我的意思是我可以通过直接传递初始化块中的对象来修复它。 有许多函数正在初始化A类,并且传递了一个哈希选项,因为我正在以当前的方式执行它。

有没有办法期望在rspec中传递的对象的内容而不是验证对象是否相同?在初始化中直接传递对象是一种更好的方法吗?

2 个答案:

答案 0 :(得分:1)

您可以定义任意期望处理以检查所选参数的值(请参阅here):

it 'configures object with passed params' do
  expect_any_instance_of(B).to receive(:configure) do |config|
     expect(config).to be_a(C)
     expect(config.url).to eq(configuration[:url])
     expect(config.headers).to eq(configuration[:headers])
     # ...
  end

  A.new(
    options,
    configuration
  )
end

答案 1 :(得分:0)

您需要B.configure(config)下的配置哈希(而不是对象),因此您的类必须稍微更改以适应。

班级档案

class A
  attr_accessor :client

  def initialize(options, configuration)
    self.client = B.new(options)
    config = C.new(
      url: configuration[:url],
      headers: configuration[:headers],
      username: configuration[:username],
      password: configuration[:password]
    )
    client.configure(config.options)
  end
end

class C
  attr_reader :options

  def initialize(options)
    @options = options
  end
end

class B
  def initialize(options)
    # does something with options hash
  end

  def configure(config)
    # some configuration with config object
  end
end

以下是您的RSpec代码的样子。

describe do
  let(:options) do
    {
      force_basic_auth: true
    }
  end

  let(:configuration) do
    {
      url: 'https://localhost:3000',
      headers: { awesome: true },
      username: 'test',
      password: 'pass'
    }
  end

  let(:my_a_object) { A.new(options, configuration) }
  let(:my_b_object) { B.new(options) }

  it 'configures object with passed params' do
    allow(B).to receive(:new).with(options).and_return(my_b_object)

    expect(my_b_object).to receive(:configure).with(configuration)
    my_a_object
  end
end
相关问题