rspec 存根以允许 [hash_key] 被传递
rspec stub to allow [hash_key] to be passed
您如何创建一个 rspec 方法存根以允许从接受散列键到 return 其值的方法的响应?
这是我要测试的线路
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 中 运行 我的代码,我可以看到它可以工作,但我找不到方法让我的 class double 接收哈希键。
你的存根有点太深了,想想这个吧
allow(menu).to receive(:menu_items).and_return({Beer: 2.0})
行menu.menu_items[item]
实际上是由3个方法调用组成的。 []
是对 menu_items
返回的 Hash
方法 []
的调用。
我假设 menu.menu_items
returns 是 Hash
而不是 Array
,在规范 item
中给出的是 Symbol
。
这意味着您的存根需要多做一些工作。
allow(menu).to receive(:menu_items).and_return({ Beer: 2.0 })
另请注意,错误
undefined local variable or method `item'
是因为您在规范中使用了 item
,但 item
未在您的方法之外定义。
感谢@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
你可以这样做:
allow(menu.menu_items).to receive(:[]).and_return({Beer: 2.0})
如果需要,您也可以传递特定项目:
allow(menu.menu_items).to receive(:[]).with(1).and_return({Beer: 2.0})
您如何创建一个 rspec 方法存根以允许从接受散列键到 return 其值的方法的响应?
这是我要测试的线路
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 中 运行 我的代码,我可以看到它可以工作,但我找不到方法让我的 class double 接收哈希键。
你的存根有点太深了,想想这个吧
allow(menu).to receive(:menu_items).and_return({Beer: 2.0})
行menu.menu_items[item]
实际上是由3个方法调用组成的。 []
是对 menu_items
返回的 Hash
方法 []
的调用。
我假设 menu.menu_items
returns 是 Hash
而不是 Array
,在规范 item
中给出的是 Symbol
。
这意味着您的存根需要多做一些工作。
allow(menu).to receive(:menu_items).and_return({ Beer: 2.0 })
另请注意,错误
undefined local variable or method `item'
是因为您在规范中使用了 item
,但 item
未在您的方法之外定义。
感谢@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
你可以这样做:
allow(menu.menu_items).to receive(:[]).and_return({Beer: 2.0})
如果需要,您也可以传递特定项目:
allow(menu.menu_items).to receive(:[]).with(1).and_return({Beer: 2.0})