tests test run rails matchers how ruby-on-rails ruby activerecord rspec observer-pattern

ruby-on-rails - test - rspec rails 5



¿Cómo evaluarías a los observadores con rSpec en una aplicación Ruby on Rails? (4)

Supongamos que tiene un ActiveRecord :: Observer en una de sus aplicaciones de Ruby on Rails: ¿cómo prueba este observador con rSpec?


Descargo de responsabilidad: nunca he hecho esto en un sitio de producción, pero parece que una forma razonable sería usar objetos simulados, should_receive y friends, e invocar métodos en el observador directamente

Dado el siguiente modelo y observador:

class Person < ActiveRecord::Base def set_status( new_status ) # do whatever end end class PersonObserver < ActiveRecord::Observer def after_save(person) person.set_status("aha!") end end

Escribiría una especificación como esta (la ejecuté y pasó)

describe PersonObserver do before :each do @person = stub_model(Person) @observer = PersonObserver.instance end it "should invoke after_save on the observed object" do @person.should_receive(:set_status).with("aha!") @observer.after_save(@person) end end


Está en el camino correcto, pero me he encontrado con una cantidad de frustrantes errores de mensajes inesperados al usar rSpec, observadores y objetos simulados. Cuando estoy probando la especificación de mi modelo, no quiero tener que manejar el comportamiento del observador en las expectativas de mi mensaje.

En su ejemplo, no hay una manera realmente buena de especificar "set_status" en el modelo sin conocimiento de lo que el observador le hará.

Por lo tanto, me gusta utilizar el complemento "No Peeping Toms". Dado su código anterior y utilizando el complemento No Peeping Toms, especifico el modelo así:

describe Person do it "should set status correctly" do @p = Person.new(:status => "foo") @p.set_status("bar") @p.save @p.status.should eql("bar") end end

Puedes especificar el código de tu modelo sin tener que preocuparte de que haya un observador que vaya a entrar y arruinar tu valor. Deberías especificar eso por separado en person_observer_spec como este:

describe PersonObserver do it "should clobber the status field" do @p = mock_model(Person, :status => "foo") @obs = PersonObserver.instance @p.should_receive(:set_status).with("aha!") @obs.after_save end end

Si REALMENTE REALMENTE desea probar la clase acoplada Model y Observer, puede hacerlo así:

describe Person do it "should register a status change with the person observer turned on" do Person.with_observers(:person_observer) do lambda { @p = Person.new; @p.save }.should change(@p, :status).to("aha!) end end end

99% del tiempo, preferiría probar con los observadores apagados. Es más fácil de esa manera.


Si desea probar que el observador observa el modelo correcto y recibe la notificación como se esperaba, aquí hay un ejemplo que usa RR.

your_model.rb:

class YourModel < ActiveRecord::Base ... end

your_model_observer.rb:

class YourModelObserver < ActiveRecord::Observer def after_create ... end def custom_notification ... end end

your_model_observer_spec.rb:

before do @observer = YourModelObserver.instance @model = YourModel.new end it "acts on the after_create notification" mock(@observer).after_create(@model) @model.save! end it "acts on the custom notification" mock(@observer).custom_notification(@model) @model.send(:notify, :custom_notification) end