I want to use FactoryGirl.attributes_for in controller testing, as in:
it "raise error creating a new PremiseGroup for this user" do
expect {
post :create, {:premise_group => FactoryGirl.attributes_for(:premise_group)}
}.to raise_error(CanCan::AccessDenied)
end
... but this doesn't work because #attributes_for omits the :user_id attribute. Here is the difference between #create
and #attributes_for
:
>> FactoryGirl.create(:premise_group)
=> #<PremiseGroup id: 3, name: "PremiseGroup_4", user_id: 6, is_visible: false, is_open: false)
>> FactoryGirl.attributes_for(:premise_group)
=> {:name=>"PremiseGroup_5", :is_visible=>false, :is_open=>false}
Note that the :user_id is absent from #attributes_for
. Is this the expected behavior?
FWIW, my factories file includes definitions for :premise_group
and for :user
:
FactoryGirl.define do
...
factory :premise_group do
sequence(:name) {|n| "PremiseGroup_#{n}"}
user
is_visible false
is_open false
end
factory :user do
...
end
end
By design, FactoryGirl's attribues_for
intentionally omits things that would trigger a database transaction so tests will run fast. But you can can write a build_attributes
method (below) to model all the attributes, if you're willing to take the time hit.
Digging deep into the FactoryGirl documentation, e.g. this wiki page, you will find mentions that attributes_for
ignores associations -- see update below. As a workaround, I've wrapped a helper method around FactoryGirl.build(...).attributes
that strips id
, created_at
, and updated_at
:
def build_attributes(*args)
FactoryGirl.build(*args).attributes.delete_if do |k, v|
["id", "created_at", "updated_at"].member?(k)
end
end
So now:
>> build_attributes(:premise_group)
=> {"name"=>"PremiseGroup_21", "user_id"=>29, "is_visible"=>false, "is_open"=>false}
... which is exactly what's expected.
Having absorbed the comments from the creators of FactoryGirl, I understand why attributes_for
ignores associations: referencing an association generates a call to the db which can greatly slow down tests in some cases. But if you need associations, the build_attributes
approach shown above should work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With