我正在测试缓存过期,在创建新的ProjectInfo时,项目和ProjectInfos的缓存都应该过期。我有以下测试:
it "creating a new project info should invalidate the cache" do
2.times { FactoryGirl.create(:project_info) }
ProjectInfo.should_receive(:all).and_call_original
Project.should_receive(:all).and_call_original
Project.fetch_all
Project.should_not_receive(:all)
Project.fetch_all
ProjectInfo.should_not_receive(:all)
ProjectInfo.fetch_all
FactoryGirl.create(:project_info)
Project.should_receive(:all).and_call_original
Project.fetch_all <- problem line
ProjectInfo.should_receive(:all).and_call_original
ProjectInfo.fetch_all
end
我收到以下错误:
1) ProjectInfo Caching creating a new project should invalidate the cache
Failure/Error: Project.fetch_all
Project(id:integer, name:string).all({:include => :project_info})
expected: 0 times with any arguments
received: 1 time with arguments: ({:include=>:project_info})
如果最后一个Project.fetch_all有问题的行。为什么rspec期待它0次?
答案 0 :(得分:1)
<强>摘要强>
在同一示例中对同一对象设置否定期望后,无法为对象设置正期望值。
<强>详细强>
我不知道RSpec的行为是在对已经设定了预期的事物设定期望时正式定义的。我制作了一组测试,其结果如下所示,试图提出一个统一的模型。
从概念上讲,似乎RSpec似乎将每个对象#方法的期望放入一个特定于对象#方法的FIFO队列中,然后在每个方法调用和块结束时检查对该队列的期望。如果“满足”对队列中的条目的期望,则期望递减或移除(如果递减变为0)。如果没有达到预期,那么期望就会失败。
鉴于这种情况,如果调用该方法,则在“should_not_receive”之后放置“should_receive”将始终失败,如您的情况。
此问题的解决方案和RSpec预期的方法是将您的单个示例分解为多个示例,这样您就不会在同一个示例中对同一个对象#方法对设置两次期望。
请注意,在下面的示例中,我在RSpec报告错误的行上显示错误。在不期望的调用的情况下,这将是调用的行。如果设置了调用的期望但是块的结尾没有满足,那将是设置期望的行。
class Foo; end
describe "multiple expectations on same object with single it clause" do
it "yes, doit" do # succeeds
Foo.should_receive(:bar)
Foo.bar
end
it "no, yes, doit" do
Foo.should_not_receive(:bar)
Foo.should_receive(:bar)
Foo.bar # fails, expected 0, received 1
end
it "yes, doit, no" do # succeeds
Foo.should_receive(:bar)
Foo.bar
Foo.should_not_receive(:bar)
end
it "yes, doit, yes, doit" do # succeeds
Foo.should_receive(:bar)
Foo.bar
Foo.should_receive(:bar)
Foo.bar
end
it "yes, yes, doit, doit" do # succeeds
Foo.should_receive(:bar)
Foo.should_receive(:bar)
Foo.bar
Foo.bar
end
it "yes, yes, doit" do
Foo.should_receive(:bar)
Foo.should_receive(:bar) # fails, expected 1, received 0
Foo.bar
end
it "yes, yes" do
Foo.should_receive(:bar) # fails, expected 1, received 0
Foo.should_receive(:bar)
end
it "yes, no" do
Foo.should_receive(:bar) # fails, expected 1, received 0
Foo.should_not_receive(:bar)
end
it "no, yes" do
Foo.should_not_receive(:bar)
Foo.should_receive(:bar) # fails, expected 1, received 0
end
it "yes(2), doit, yes, doit, doit" do # succeeds
Foo.should_receive(:bar).exactly(2).times
Foo.bar
Foo.should_receive(:bar)
Foo.bar
Foo.bar
end
end
答案 1 :(得分:0)
我认为Project.should_not_receive(:all)
fetch_all
可能会调用all
。
您可以在没有Project.should_not_receive(:all)