37 votes

Comment voulez-vous tester les observateurs avec rSpec en Ruby on Rails application?

Supposons que vous avez un ActiveRecord::Observateur dans l'une de vos Ruby on Rails applications - comment pouvez-vous tester cet observateur avec rSpec?

35voto

Pete Points 1250

Vous êtes sur la bonne voie, mais j'ai couru dans un certain nombre de frustrant inattendu message d'erreurs lors de l'utilisation de rSpec, les observateurs et les objets fantaisie. Quand je suis spec de tester mon modèle, je ne veux pas avoir à gérer observateur comportement dans mon message attentes.

Dans votre exemple, il n'y a pas une très bonne façon de spec "set_status" sur le modèle sans la connaissance de ce que l'observateur va faire pour elle.

Par conséquent, je tiens à utiliser le "Pas de Peeping Toms" plugin. Compte tenu de votre code ci-dessus et en utilisant le Pas de Peeping Toms plugin, je voudrais spec le modèle comme ceci:

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

Vous pouvez spec votre modèle de code sans avoir à se soucier qu'il y a un observateur qui va venir dans et tabasser votre valeur. Vous auriez spec séparément dans le person_observer_spec comme ceci:

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 VRAIMENT vous voulez VRAIMENT tester le Modèle couplé et Observateur de la classe, vous pouvez le faire comme ceci:

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% du temps, je préfère spec test avec les observateurs éteint. C'est juste plus facile de cette façon.

15voto

Orion Edwards Points 54939

Disclaimer: je ne l'ai jamais fait ça sur un site de production, mais il semble que, d'une manière raisonnable serait d'utiliser les objets fantaisie, should_receive et les amis, et appeler des méthodes sur l'observateur directement

Étant donné le modèle suivant et de l'observateur:

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

Je voudrais écrire une spécification comme ceci (j'ai couru, et ça passe)

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

4voto

William Dix Points 41

no_peeping_toms est maintenant un bijou et peut être trouvé ici: https://github.com/patmaddox/no-peeping-toms

2voto

Sujoy Gupta Points 981

Si vous voulez tester que l'observateur observe le bon modèle et reçoit la notification comme prévu, voici un exemple d'utilisation de la 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X