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
porquecreate
osave
también activará este método, odo_something
con las acciones duplicadas de DB. - Cambiar
create
parabuild
- Prueba respond_to
Utilice
model.save
general en lugar demodel.do_something
llamada individualmodel.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:
- ¿Se está activando la devolución de llamada para los eventos correctos?
- ¿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