如何模拟调用我正在使用RSpec测试的函数参数 我是这样做的:
module Module1
def find_item(str, item_class)
arr = item_class.find_or_initialize_by(...)
end
end
然后在规格中:
let!(:dummy_class) { Class.new { extend Module1 } }
it 'calls find_or_initialize_by' do
item_class = double("Item")
allow(dummy_class).to receive(:item_class).and_return(item_class)
expect(item_class).to receive(:find_or_initialize_by)
dummy_class.find_item("item1", Item)
end
它引发错误“#does not implement:item_class” 我试图使用class_double和instance_double,但它没有用。
故障:
1)Module1#find_items 失败/错误:允许(dummy_class).to receive(:item_class) #没有实现:item_class #./spec/..._spec.rb:26:在'
中的块(3级)
26行:allow(dummy_class).to receive(:item_class).and_return(item_class)
答案 0 :(得分:1)
不知道你为什么要这样做,但你并不太远。
目前您正在尝试使用
allow(dummy_class).to receive(:item_class).and_return(item_class)
但item_class
不是一种local_variable
的方法。
Message Allowance简而言之,语法为allow(object).to receive(method_name).with(arguments).and_return(return_value)
和Message Expectation语法为expect(object).to receive(method_name).with(arguments).and_return(return_value)
所以也许你的意思是allow(dummy_class).to receive(:find_item).with(item_class).and_return(item_class)
,因为find_item
是实际被调用的方法而item_class
是传入的参数,但是因为你正在查看返回值然后是方法永远不会发生
您还可以allow(dummy_class).to recieve(:find_item).and_call_original
,但这并不是真正有用的,因为dummy_class
不是双倍的,并且已经“允许”调用其find_item
的原始版本。
因此,让我们继续使用dummy_class
和allow(item_class).to receive(:find_or_initialize_by)
的原生功能,然后以下内容将起作用。
it 'calls find_or_initialize_by' do
item_class = double("Item")
allow(item_class).to recieve(:find_or_initialize_by) #needed because it is a test double and knows nothing
expect(item_class).to receive(:find_or_initialize_by)
dummy_class.find_item("item1", item_class) #used test double here to trap messages
end
或者,我们可以使用Item
的部分双倍,并跳过Test Double item_class
,例如。
#please note this binds the test to Item existing
it 'calls find_or_initialize_by' do
allow(Item).to receive(:find_or_initialize_by) #now a stubbed method on a partial double(Item)
expect(Item).to receive(:find_or_initialize_by)
dummy_class.find_item("item1", Item) #used the partial double
end
Partial doubles很好,因为它们可以验证双打,并确保Object
在存根之前实际定义该方法。
考虑到你的考试的性质以及dummy_class
不是一个双重(因此不需要allow
任何东西)并且你没有测试任何返回值而只是调用我会这么说建议只使用Spy,因为它们仅用于预期消息。
这使得测试更简单,更清晰,没有任何依赖性:
it 'calls find_or_initialize_by' do
item = spy("item")
dummy_class.find_item("item1", item)
expect(item).to have_received(:find_or_initialize_by)
end
它们也有部分双重味道,但这取决于Item
是已知并加载Object
:(非常类似于上述但预期是呼叫的后效)
#please note this binds the test to Item existing
it 'calls find_or_initialize_by' do
allow(Item).to receive(:find_or_initialize_by)
dummy_class.find_item("item1", Item)
expect(Item).to have_received(:find_or_initialize_by)
end
另外,假设(...)
中的Module1
看起来像name: str
,那么我建议测试它是否也使用正确的参数进行调用,例如
it 'calls find_or_initialize_by with args' do
item = spy("item")
dummy_class.find_item("item1", item)
expect(item).to have_received(:find_or_initialize_by).with(name: 'item1')
end
这样可以确保不仅进行了调用,而且还将预期的参数传递给了调用。
特别是对Module
测试消息期望我会尝试保持测试双打和间谍,因为它会使您的测试独立且快速(当Item
不再存在时会发生什么?)