我在 Rails 中有一个导入控制器,可以将多个包含多条记录的 csv 文件导入我的数据库。如果记录实际上是使用 RSpec 保存的,我想在 RSpec 中测试:
<Model>.any_instance.should_receive(:save).at_least(:once)
但是我收到错误消息:
The message 'save' was received by <model instance> but has already been received by <another model instance>
控制器的人为示例:
rows = CSV.parse(uploaded_file.tempfile, col_sep: "|")
ActiveRecord::Base.transaction do
rows.each do |row|
mutation = Mutation.new
row.each_with_index do |value, index|
Mutation.send("#{attribute_order[index]}=", value)
end
mutation.save
end
是否可以使用 RSpec 对此进行测试,或者是否有任何解决方法?
这是一个更好的答案,可以避免重写 :new 方法:
save_count = 0
<Model>.any_instance.stub(:save) do |arg|
# The evaluation context is the rspec group instance,
# arg are the arguments to the function. I can't see a
# way to get the actual <Model> instance :(
save_count+=1
end
.... run the test here ...
save_count.should > 0
似乎存根方法可以附加到没有约束的任何实例,并且 do 块可以进行计数,您可以检查它以断言它被调用了正确的次数。
更新 - 新的 rspec 版本需要以下语法:
save_count = 0
allow_any_instance_of(Model).to receive(:save) do |arg|
# The evaluation context is the rspec group instance,
# arg are the arguments to the function. I can't see a
# way to get the actual <Model> instance :(
save_count+=1
end
.... run the test here ...
save_count.should > 0
有一个新的语法:
expect_any_instance_of(Model).to receive(:save).at_least(:once)
expect_any_instance_of
。这是一个link to the doc。
我终于设法进行了一个适合我的测试:
mutation = FactoryGirl.build(:mutation)
Mutation.stub(:new).and_return(mutation)
mutation.should_receive(:save).at_least(:once)
存根方法返回一个实例,该实例多次接收保存方法。因为它是单个实例,所以我可以删除 any_instance
方法并正常使用 at_least
方法。
这是 Rob 使用 RSpec 3.3 的示例,它不再支持 Foo.any_instance
。我发现这在循环创建对象时很有用
# code (simplified version)
array_of_hashes.each { |hash| Model.new(hash).write! }
# spec
it "calls write! for each instance of Model" do
call_count = 0
allow_any_instance_of(Model).to receive(:write!) { call_count += 1 }
response.process # run the test
expect(call_count).to eq(2)
end
像这样的存根
User.stub(:save) # Could be any class method in any class
User.any_instance.stub(:save) { |*args| User.save(*args) }
然后期待这样:
# User.any_instance.should_receive(:save).at_least(:once)
User.should_receive(:save).at_least(:once)
这是 this gist 的简化,使用 any_instance
,因为您不需要代理到原始方法。有关其他用途,请参阅该要点。
我的情况有点不同,但我最终在这个问题上也想在这里放弃我的答案。就我而言,我想存根给定类的任何实例。我在使用 expect_any_instance_of(Model).to
时遇到了同样的错误。当我将其更改为 allow_any_instance_of(Model).to
时,我的问题就解决了。
查看文档了解更多背景信息:https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class
expect_any_instance_of(Widget).to receive(:name).twice
中,不清楚是否每个特定实例预计会收到 name
两次,或者如果预计总共收到两次。(是前者。)“
您可以尝试计算班级中 new
的数量。这实际上并没有测试 save
的数量,但可能就足够了
expect(Mutation).to receive(:new).at_least(:once)
如果唯一的期望是它被保存了多少次。那么您可能想要使用 spy()
而不是功能齐全的工厂,如 Harm de Wit
自己的答案
allow(Mutation).to receive(:new).and_return(spy)
...
expect(Mutation.new).to have_received(:save).at_least(:once)
不定期副业成功案例分享