W jaki sposób można przetestować RSpec w aplikacji Ruby on Rails?

Załóżmy, że masz ActiveRecord:: Observer w jednej z Twoich aplikacji Ruby on Rails - jak przetestować tego obserwatora za pomocą rSpec?

Author: Nicolai Reuschling, 2008-08-28

4 answers

Jesteś na dobrej drodze, ale napotkałem wiele frustrujących nieoczekiwanych błędów komunikatów podczas korzystania z rSpec, obserwatorów i mock obiektów. Kiedy testuję mój model, nie chcę zajmować się zachowaniem obserwatorów w moich oczekiwaniach dotyczących wiadomości.

W twoim przykładzie, nie ma naprawdę dobrego sposobu na określenie" set_status " na modelu bez wiedzy o tym, co obserwator zamierza z nim zrobić.

Dlatego lubię używać wtyczki "No Peeping Toms". Given Twój kod powyżej i używając wtyczki No Peeping Toms, chciałbym określić model w ten sposób:

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

Możesz określić kod modelu bez obawy, że istnieje obserwator, który przyjdzie i zatrze twoją wartość. Opisałbyś to osobno w osobowości_observer_spec tak:

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 

Jeśli naprawdę chcesz przetestować model sprzężony i klasę Observer, możesz to zrobić tak:

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
[[3]} 99% czasu, wolałbym spec test z obserwatorzy wyłączeni. Tak jest łatwiej.
 35
Author: Pete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 12:43:49

Zastrzeżenie: nigdy tak naprawdę nie robiłem tego na stronie produkcyjnej, ale wygląda na to, że rozsądnym sposobem byłoby użycie mock objects, should_receive i friends, i wywołanie metod bezpośrednio na obserwatorze

Biorąc pod uwagę następujący model I Obserwator:

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

Napisałbym taki spec (uruchomiłem go i mija)

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
 15
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-10 00:09:33

No_peeping_toms jest teraz klejnotem i można go znaleźć tutaj: https://github.com/patmaddox/no-peeping-toms

 4
Author: William Dix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-05 16:51:22

Jeśli chcesz sprawdzić, czy obserwator przestrzega poprawnego modelu i otrzymuje powiadomienie zgodnie z oczekiwaniami, oto przykład użycia 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
 2
Author: Sujoy Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-08 22:31:46