tutorial rails factorybot example bot ruby-on-rails ruby-on-rails-3 activerecord rspec factory-bot

ruby-on-rails - rails - faker rspec



¿Cómo probar el método de devolución de llamada del modelo de forma independiente? (4)

Tenía un método en un modelo:

class Article < ActiveRecord::Base def do_something end end

También tuve una prueba unitaria para este método:

# spec/models/article_spec.rb describe "#do_something" do @article = FactoryGirl.create(:article) it "should work as expected" do @article.do_something expect(@article).to have_something end # ...several other examples for different cases end

Todo estuvo bien hasta que encontré que es mejor mover este método a una after_save llamada after_save :

class Article < ActiveRecord::Base after_save :do_something def do_something end end

Ahora todas mis pruebas sobre este método se han roto. Tengo que arreglarlo por:

  • No más llamadas específicas para hacer do_something porque create o save también activará este método, o do_something con las acciones duplicadas de DB.
  • Cambiar create para build
  • Prueba respond_to
  • Utilice model.save general en lugar de model.do_something llamada individual model.do_something

    describe "#do_something" do @article = FactoryGirl.build(:article) it "should work as expected" do expect{@article.save}.not_to raise_error expect(@article).to have_something expect(@article).to respond_to(:do_something) end end

La prueba pasó, pero mi preocupación es que ya no se trata del método específico. El efecto se mezclará con otras devoluciones de llamada si se agrega más .

Mi pregunta es, ¿hay alguna manera hermosa de probar los métodos de instancia del modelo de forma independiente que se conviertan en una devolución de llamada?


El comportamiento de devolución de llamada y devolución de llamada son pruebas independientes. Si desea verificar una devolución de llamada after_save, debe considerarla como dos cosas:

  1. ¿Se está activando la devolución de llamada para los eventos correctos?
  2. ¿La función llamada está haciendo lo correcto?

Supongamos que tiene la clase de Article con muchas devoluciones de llamada, así es como lo haría:

class Article < ActiveRecord::Base after_save :do_something after_destroy :do_something_else ... end it "triggers do_something on save" do expect(@article).to receive(:do_something) @article.save end it "triggers do_something_else on destroy" do expect(@article).to receive(:do_something_else) @article.destroy end it "#do_something should work as expected" do # Actual tests for do_something method end

Esto desacopla tus devoluciones de llamada del comportamiento. Por ejemplo, podría desencadenar el mismo article.do_something cuando se actualice algún otro objeto relacionado, digamos como user.before_save { user.article.do_something } . Esto acomodará todos esos.

Por lo tanto, siga probando sus métodos como de costumbre. Preocuparse por las devoluciones de llamadas por separado.

Editar: errores ortográficos y conceptos erróneos potenciales Editar: cambiar "hacer algo" para "desencadenar algo"


Esto es más un comentario que una respuesta, pero lo puse aquí para resaltar la sintaxis ...

Quería una manera de omitir las devoluciones de llamada en mis pruebas, esto es lo que hice. (Esto podría ayudar con las pruebas que se rompieron).

class Article < ActiveRecord::Base attr_accessor :save_without_callbacks after_save :do_something def do_something_in_db unless self.save_without_callbacks # do something here end end end # spec/models/article_spec.rb describe Article do context "after_save callback" do [true,false].each do |save_without_callbacks| context "with#{save_without_callbacks ? ''out'' : nil} callbacks" do let(:article) do a = FactoryGirl.build(:article) a.save_without_callbacks = save_without_callbacks end it do if save_without_callbacks # do something in db else # don''t do something in db end end end end end end


Puede usar shoulda-callback-matchers para probar la existencia de sus callbacks sin llamarlos.

describe Article do it { should callback(:do_something).after(:save) } end

Si también desea probar el comportamiento de la devolución de llamada:

describe Article do ... describe "#do_something" do it "gives the article something" do @article.save expect(@article).to have_something end end end


describe "#do_something" do it "gives the article something" do @article = FactoryGirl.build(:article) expect(@article).to have_something @article.save end end