Rails: Как проверить state_machine?
Пожалуйста, помогите мне. Я смущен. Я знаю, как писать поведение модели, управляемое положением, но я не знаю, что мне писать в спецификациях...
Мой файл model.rb выглядит
class Ratification < ActiveRecord::Base
belongs_to :user
attr_protected :status_events
state_machine :status, :initial => :boss do
state :boss
state :owner
state :declarant
state :done
event :approve do
transition :boss => :owner, :owner => :done
end
event :divert do
transition [:boss, :owner] => :declarant
end
event :repeat do
transition :declarant => :boss
end
end
end
Я использую state_machine gem.
Пожалуйста, покажите мне курс.
Ответы
Ответ 1
Вопрос старый, но у меня был тот же самый. Пример из state_machine gem:
class Vehicle
state_machine :state, :initial => :parked do
event :park do
transition [:idling, :first_gear] => :parked
end
event :ignite do
transition :stalled => same, :parked => :idling
end
event :idle do
transition :first_gear => :idling
end
event :shift_up do
transition :idling => :first_gear, :first_gear => :second_gear, :second_gear => :third_gear
end
event :shift_down do
transition :third_gear => :second_gear, :second_gear => :first_gear
end
end
end
Мое решение было:
describe Vehicle do
before :each do
@vehicle = Factory(:vehicle)
end
describe 'states' do
describe ':parked' do
it 'should be an initial state' do
# Check for @vehicle.parked? to be true
@vehicle.should be_parked
end
it 'should change to :idling on :ignite' do
@vehicle.ignite!
@vehicle.should be_idling
end
['shift_up!', 'shift_down!'].each do |action|
it "should raise an error for #{action}" do
lambda {@job_offer.send(action)}.should raise_error
end
end
end
end
end
Я использовал:
- ruby (1.9.3)
- рельсы (3.1.3)
- rspec (2.8.0.rc1)
- factory_girl (2.3.2)
- state_machine (1.1.0)
Ответ 2
state_machine_rspec gem включает в себя множество вспомогательных методов для написания кратких спецификаций.
describe Ratification do
it { should have_states :boss, :declarant, :done, :owner }
it { should handle_events :approve, when: :boss }
it { should handle_events :approve, when: :owner }
it { should handle_events :divert, when: :boss }
it { should handle_events :divert, when: :owner }
it { should handle_events :repeat, when: :declarant }
it { should reject_events :approve, :divert, :repeat, when: :done }
it { should reject_events :approve, :divert, :repeat, when: :done }
end
Эти контроллеры RSpec помогут с параметрами state_machine
с высокого уровня. Отсюда нужно написать спецификации для бизнес-кейсов для can_approve?
, can_divert?
и can_repeat?
.
Ответ 3
Я написал специальный сопоставитель RSpec. Это позволяет проверять поток состояния элегантным и простым способом: проверить его
Ответ 4
К сожалению, я думаю, вам нужно поставить тест для каждого состояния → переход состояния, который может выглядеть как дублирование кода.
describe Ratification do
it "should initialize to :boss" do
r = Ratification.new
r.boss?.should == true
end
it "should move from :boss to :owner to :done as it approved" do
r = Ratification.new
r.boss?.should == true
r.approve
r.owner?.should == true
r.approve
r.done?.should == true
end
# ...
end
К счастью, я думаю, что это обычно подходит для тестирования интеграции. Например, чрезвычайно простой конечный автомат для платежной системы:
class Bill < ActiveRecord::Base
belongs_to :account
attr_protected :status_events
state_machine :status, :initial => :unpaid do
state :unpaid
state :paid
event :mark_as_paid do
transition :unpaid => :paid
end
end
end
У вас могут быть тесты модулей, как указано выше, но вы, вероятно, также проведете интеграционное тестирование, например:
describe Account do
it "should mark the most recent bill as paid" do
@account.recent_bill.unpaid?.should == true
@account.process_creditcard(@credit_card)
@account.recent_bill.paid?.should == true
end
end
Это было много рук, но, надеюсь, это имеет смысл. Я также не очень привык к RSpec, поэтому, надеюсь, я не допустил слишком много ошибок. Если есть более элегантный способ проверить это, я еще не нашел его.