I’m having some problems testing StateMachines with Factory Girl. it looks like it’s down to the way Factory Girl initializes the objects.
Am I missing something, or is this not as easy as it should be?
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
So, the initial state depends on whether the stolen attribute is set during initialization. This seems to work fine, because ActiveRecord sets attributes as part of its initializer:
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'
However because Factory Girl initializes the object before individually setting its overrides (see factory_girl/proxy/build.rb), that means the flow is more like:
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
You may be able to just add an after_build callback on your factory:
However, I don’t think you should rely on setting your initial state in this way. It is very common to use ActiveRecord objects like FactoryGirl does (i.e. by calling c = Car.net; c.my_column = 123).
I suggest you allow your initial state to be nil. Then use an active record callback to set the state to to the desired value.
I think this will give you more predictable results.
One caveat is that working with unsaved Car objects will be difficult because the state won’t be set yet.