Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rspec stub to allow [hash_key] to be passed

Tags:

ruby

rspec

How do you create a rspec method stub to allow a response from a method that takes in the hash key to return its value?

This is the line I want to test

sub_total = menu.menu_items[item] * quantity

and I'm using this line in rspec as my test stub on a double.

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

My env is set up with ruby 2.2.0 and spec 3.1.7

However I keep on getting a

NameError: undefined local variable or method `item'

Ruby code

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

Rspec code

 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

Failures:

  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)>'

I've tried a number of things but nothing has worked

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)

I've run my code in irb and I can see it works but I can't find a way to get my class double to recerive the hash key.

like image 532
pie109 Avatar asked Feb 14 '15 19:02

pie109


2 Answers

The line menu.menu_items[item] is in reality composed by 3 method calls. [] is a call to the method [] on the Hash returned by menu_items.

I assume menu.menu_items returns a Hash and not an Array, given in the spec item is a Symbol.

That means your stub requires a little bit more work.

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

Also note, the error

undefined local variable or method `item'

is because you were using item in the spec, but item is not defined outside your method.

like image 117
Simone Carletti Avatar answered Nov 17 '22 00:11

Simone Carletti


you can do this:

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

You can also pass an specific item if you need:

allow(menu.menu_items).to receive(:[]).with(1).and_return({Beer: 2.0})
like image 40
demonodojo Avatar answered Nov 17 '22 00:11

demonodojo