rspec stub允许传递[hash_key]

时间:2015-02-14 19:16:20

标签: ruby rspec

如何创建一个rspec方法存根以允许来自接受哈希键的方法的响应返回其值?

这是我要测试的行

sub_total = menu.menu_items[item] * quantity

我在rspec中使用这一行作为我的测试存根。

allow(menu).to receive(:menu_items[item]).and_return(2.0)

我的环境设置为ruby 2.2.0和规范3.1.7

但是我继续得到

NameError: undefined local variable or method `item'

Ruby代码

def place_order(item, quantity, menu)
   sub_total = menu.menu_items[item] * quantity
   @customer_order << [item, quantity, sub_total]
 end

Rspec代码

 let(:menu) { double :menu }

   it "should allow 1 order of beer to placed" do
     order = Order.new
     allow(menu).to receive(:menu_items[item]).and_return(2.0)
     order.place_order(:Beer, 1, 2.0)
     expect(order.customer_order).to eq [[:Beer, 1, 2.0]]
  end

故障:

  1) Order should allow 1 order of beer to placed
     Failure/Error: allow(menu).to receive(:menu_items[item]).and_return(2.0)
     NameError:
       undefined local variable or method `item' for #<RSpec::ExampleGroups::Order:0x007fbb62917ee8 @__memoized=nil>
     # ./spec/order_spec.rb:9:in `block (2 levels) in <top (required)>'

我尝试过很多东西,但没有任何效果

allow(menu).to receive(:menu_items).and_return(2.0)
allow(menu).to receive(:menu_items).with(item).and_return(2.0)
allow(menu).to receive(:menu_items).with("item").and_return(2.0)
allow(menu).to receive(:menu_items).with([item]).and_return(2.0)

我在irb中运行我的代码,我可以看到它有效但我找不到让我的类加倍来接收哈希键的方法。

4 个答案:

答案 0 :(得分:6)

menu.menu_items[item]实际上由3个方法调用组成。 []是对Hash返回的menu_items上的[]方法的调用。

我认为menu.menu_items返回Hash而不是Array,规范item中给出的是Symbol

这意味着你的存根需要更多的工作。

allow(menu).to receive(:menu_items).and_return({ Beer: 2.0 })

另请注意,错误

undefined local variable or method `item'

是因为您在规范中使用了item,但未在您的方法之外定义item

答案 1 :(得分:0)

你的存根有点太深了,想一想

allow(menu).to receive(:menu_items).and_return({Beer: 2.0})

答案 2 :(得分:0)

感谢@ SimoneCarletti的回答,我能够轻松地存根PublicActivity的实例。我将此答案仅作为OP问题的简要(重新)陈述和解决方案的简单性添加。

代码我想模仿存根:

self.entity = activity.parameters['entity_string']

测试的重要部分加倍:

activity = double('activity') # PublicActivity
allow(activity).to receive(:parameters).and_return({'entity_string' => "some entity name"})

完整代码:

class ActivityRenderer

  attr_accessor :time
  attr_accessor :user
  attr_accessor :action
  attr_accessor :entity

  def initialize(activity)
    self.entity = activity.parameters['entity_string']
    self.time = activity.updated_at
    self.user = User.find(activity.owner_id)
    self.action = activity.key
  end
end

RSpec.describe ActivityRenderer do
  let(:user) { ...factory girl stuff... }
  let(:now) { Time.zone.now }

  before do
    Timecop.freeze
  end

  it 'provides an activity renderer' do
    activity = double('activity') # PublicActivity
    allow(activity).to receive(:parameters).and_return({'entity_string' => "some entity name"})
    allow(activity).to receive(:updated_at).and_return(now)
    allow(activity).to receive(:owner_id).and_return(user._id)
    allow(activity).to receive(:key).and_return('some activity?')

    ar = ActivityRenderer.new(activity)

    expect(ar.user).to eql(user)
    expect(ar.time).to eql(now)
    expect(ar.action).to eql('some activity?')
    expect(ar.entity).to eql("some entity name")
  end
end

答案 3 :(得分:0)

您可以执行以下操作:

allow(menu.menu_items).to receive(:[]).and_return({Beer: 2.0})

如果需要,您还可以传递特定项目:

allow(menu.menu_items).to receive(:[]).with(1).and_return({Beer: 2.0})
相关问题