问题描述
我想在控制器测试中使用FactoryGirl.attributes_for,例如:
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
...,但这不起作用,因为#attributes_for省略了:user_id属性.这是#create
和#attributes_for
之间的区别:
... 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}
请注意,#attributes_for
中不存在:user_id.这是预期的行为吗?
Note that the :user_id is absent from #attributes_for
. Is this the expected behavior?
FWIW,我的工厂文件包含:premise_group
和:user
的定义:
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
推荐答案
简短答案:
根据设计,FactoryGirl的attribues_for
故意省略了会触发数据库事务的操作,因此测试将快速运行.但是,如果您愿意花点时间,可以编写一个build_attributes
方法(如下)来对所有属性进行建模.
Short Answer:
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.
深入研究FactoryGirl文档,例如此Wiki页面,您会发现提到attributes_for
忽略关联-请参阅更新以下.作为一种解决方法,我在FactoryGirl.build(...).attributes
周围包装了一个辅助方法,该方法去除了id
,created_at
和updated_at
:
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
所以现在:
>> build_attributes(:premise_group)
=> {"name"=>"PremiseGroup_21", "user_id"=>29, "is_visible"=>false, "is_open"=>false}
...这正是预期的结果.
... which is exactly what's expected.
吸收了FactoryGirl创建者的评论后,我了解了attributes_for
为什么忽略关联的原因:引用关联会生成对db的调用,这在某些情况下会大大降低测试速度.但是,如果您需要关联,则上面显示的build_attributes
方法应该可以.
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.
这篇关于FactoryGirl:为什么attributes_for会省略一些属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!