How to say "any_instance" "should_receive" any number of times in RSpec

Harm de Wit picture Harm de Wit · Mar 21, 2012 · Viewed 36k times · Source

I've got an import controller in rails that imports several csv files with multiple records into my database. I would like to test in RSpec if the records are actually saved by using RSpec:

<Model>.any_instance.should_receive(:save).at_least(:once)

However i get the error saying:

The message 'save' was received by <model instance> but has already been received by <another model instance>

A contrived example of the controller:

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

Is it possible to test this using RSpec or is there any workaround?

Answer

Rob picture Rob · Apr 3, 2012

Here's a better answer that avoids having to override the :new method:

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

Seems that the stub method can be attached to any instance w/o the constraint, and the do block can make a count that you can check to assert it was called the right number of times.

Update - new rspec version requires this syntax:

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