ruby-on-rails testing rspec mocking mocha

ruby on rails - Cómo decir "any_instance" "should_receive" cualquier cantidad de veces en RSpec



ruby-on-rails testing (6)

Tengo un controlador de importación en rieles que importa varios archivos csv con múltiples registros en mi base de datos. Me gustaría probar en RSpec si los registros se guardan realmente mediante el uso de RSpec:

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

Sin embargo, recibo el error diciendo:

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

Un ejemplo artificial del controlador:

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

¿Es posible probar esto usando RSpec o hay alguna solución alternativa?


Aquí hay una mejor respuesta que evita tener que anular el: nuevo método:

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

Parece que el método stub se puede adjuntar a cualquier instancia sin la restricción, y el bloque do puede hacer un conteo que se puede verificar para afirmar que se llamó el número correcto de veces.

Actualización: la nueva versión de rspec requiere esta sintaxis:

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


Este es el ejemplo de Rob que usa RSpec 3.3, que ya no es compatible con Foo.any_instance . Lo encontré útil cuando estaba en un bucle creando objetos

# 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


Finalmente logré hacer una prueba que me funciona:

mutation = FactoryGirl.build(:mutation) Mutation.stub(:new).and_return(mutation) mutation.should_receive(:save).at_least(:once)

El método stub devuelve una sola instancia que recibe el método guardar varias veces. Debido a que es una instancia única, puedo descartar el método any_instance y usar el método at_least normalmente.


Hay una nueva sintaxis para esto:

expect_any_instance_of(Model).to receive(:save).at_least(:once)


Mi caso fue un poco diferente, pero terminé con esta pregunta y pensé que soltaría mi respuesta aquí también. En mi caso, quería resguardar cualquier instancia de una clase determinada. expect_any_instance_of(Model).to el mismo error cuando utilicé expect_any_instance_of(Model).to . Cuando lo cambié a allow_any_instance_of(Model).to , mi problema fue resuelto.

Consulte la documentación para obtener más información: github.com/rspec/…


Stub como este

User.stub(:save) # Could be any class method in any class User.any_instance.stub(:save) { |*args| User.save(*args) }

Entonces espera así:

# User.any_instance.should_receive(:save).at_least(:once) User.should_receive(:save).at_least(:once)

Esta es una simplificación de esta esencia , para usar any_instance , ya que no es necesario utilizar el método original. Consulte esa idea para otros usos.