2010-06-15 9 views
16

Por favor, ayúdame. Estoy confundido. Yo sé cómo escribir un comportamiento impulsado por el Estado de modelo, pero no sé lo que debo escribir en espec ...Rieles: ¿cómo probar state_machine?

Mi archivo model.rb vistazo

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 

utilizo state_machine joya.

Por favor, muéstrame el curso.

+0

¿Alguna manera de hacer esto sin presionar la base de datos? Parece que deberíamos poder anular cualquier cosa que use state_machine para llegar a la base de datos y obtener todos los cambios que esperamos. –

Respuesta

0

Lamentablemente, creo que debe poner una prueba para cada estado -> transición de estado, lo que puede parecer una duplicación de código.

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's approved" do 
    r = Ratification.new 
    r.boss?.should == true 
    r.approve 
    r.owner?.should == true 
    r.approve 
    r.done?.should == true 
    end 

    # ... 
end 

Afortunadamente, creo que esto por lo general se ajusta a las pruebas de integración. Por ejemplo, una máquina de estado extremadamente simple para un sistema de pagos sería:

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 

es posible que aún tienen las pruebas de unidad que el anterior, pero es probable que también tienen pruebas de integración, algo así como:

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 

Eso fue mucho trabajo manual, pero espero que tenga sentido. Tampoco estoy muy acostumbrado a RSpec, así que con suerte no cometí muchos errores allí. Si hay una forma más elegante de probar esto, aún no lo he encontrado.

+2

Puede usar ... @ account.recent_bill.should be_unpaid –

9

La pregunta es vieja, pero tuve la misma. Tomando ejemplo de 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 

Mi solución fue:

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 

que estaba usando:

  • rubí (1.9.3)
  • carriles (3.1.3)
  • rspec (2.8.0.rc1)
  • fábrica_g IRL (2.3.2)
  • state_machine (1.1.0)
1

he escrito una matcher encargo RSpec. Permite probar el flujo de estado de manera elegante y simple: check it out

2

La gema state_machine_rspec incluye muchos métodos auxiliares para escribir especificaciones concisas.

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 

Estos comparadores RSpec ayudará con las especificaciones state_machine de un alto nivel. A partir de aquí, es necesario escribir las especificaciones para los casos comerciales para can_approve?, can_divert? y can_repeat?.

Cuestiones relacionadas