2008-08-28 12 views

Respuesta

35

Usted está en la derecha rastrear, pero me he encontrado con una cantidad de frustrantes mensajes de error 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 va a hacer.

Por lo tanto, me gustaría usar el "No Peeping Toms" plugin. Teniendo en cuenta el código de arriba y usando el plugin Sin mirones, me spec del 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 

Puede spec su código de modelo sin tener que preocuparse de que hay un observador que vendrá y destruirá tu valor. Se podría especificación que por separado en los 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 desea probar el modelo acoplado y la clase de observador, puede hacerlo de esta manera:

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% de el tiempo, preferiría probar con los observadores apagados. Es más fácil de esa manera.

+0

Si quiero probar los observadores, entonces un patrón que uso es 'describe PersonOb servidor { around (: each) {| spec | Person.with_observers (: person_observer) {spec.run}}} 'Esto habilita al observador para todas las pruebas dentro del bloque de descripción de PersonObserver. – roo

+0

Esta respuesta se expresa como una respuesta, pero no está claro para qué. Ciertamente no está respondiendo directamente a la pregunta ... –

15

responsabilidad: en realidad nunca he hecho esto en un lugar de producción, pero parece una forma razonable sería utilizar objetos simulados, should_receive y amigos, e invocar métodos en el observador directamente

Dada la 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 

me gustaría escribir una especificación así (me encontré con él, y que pasa)

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 
+0

Hemos estado siguiendo este enfoque y funciona maravillosamente –

2

Si desea probar que el observador observa el modelo correcto y recibe la notificación como era de esperar, aquí hay un ejemplo usando 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 
Cuestiones relacionadas