5

我在使用Factory Girl測試StateMachine s時遇到了一些問題。它看起來像Factory Girl初始化對象的方式。使用FactoryGirl和StateMachine測試動態初始狀態

我是否錯過了一些東西,或者它不是那麼容易?

class Car < ActiveRecord::Base 
    attr_accessor :stolen # This would be an ActiveRecord attribute 

    state_machine :initial => lambda { |object| object.stolen ? :moving : :parked } do 
    state :parked, :moving 
    end 
end 

Factory.define :car do |f| 
end 

因此,初始狀態取決於在初始化過程中是否設置了stolen屬性。這似乎很好地工作,因爲ActiveRecord的屬性集作爲其初始化的一部分:

Car.new(:stolen => true) 

## Broadly equivalent to 
car = Car.new do |c| 
    c.attributes = {:stolen => true} 
end 
car.initialize_state # StateMachine calls this at the end of the main initializer 
assert_equal car.state, 'moving' 

但是因爲工廠女孩前單獨設置它的覆蓋(見factory_girl/proxy/build.rb)初始化對象,這意味着流動更像是:

Factory(:car, :stolen => true) 

## Broadly equivalent to 
car = Car.new 
car.initialize_state # StateMachine calls this at the end of the main initializer 
car.stolen = true 
assert_equal car.state, 'moving' # Fails, because the car wasn't 'stolen' when the state was initialized 

回答

3

您可以只在您的工廠增加一個after_build回調:

Factory.define :car do |c| 
    c.after_build { |car| car.initialize_state } 
end 

不過,我不認爲你守ld依靠以這種方式設置你的初始狀態。使用像FactoryGirl那樣的ActiveRecord對象是非常普遍的(即通過調用c = Car.net; c.my_column = 123)。

我建議你讓你的初始狀態爲零。然後使用活動記錄回調將狀態設置爲所需的值。

class Car < ActiveRecord::Base 
    attr_accessor :stolen # This would be an ActiveRecord attribute 

    state_machine do 
    state :parked, :moving 
    end 

    before_validation :set_initial_state, :on => :create 

    validates :state, :presence => true 

    private 
    def set_initial_state 
    self.state ||= stolen ? :moving : :parked 
    end 
end 

我想這會給你更可預測的結果。

有一點需要注意的是,處理未保存的Car對象將會很困難,因爲狀態不會被設置。

0

試過phylae的回答,發現新的FactoryGirl不接受這個語法,並且after_build方法在ActiveRecord對象上不存在。這個新的語法應該工作:

Factory.define 
    factory :car do 
    after(:build) do |car| 
     car.initialize_state 
    end 
    end 
end 
相關問題