不知道你为什么要这样做,但你离得太远了。
目前你正在尝试使用
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
它们也有 Partial Double 风格,但这取决于 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 不再存在时会发生什么?)