问题描述
我想在控制器测试中使用 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
推荐答案
Short Answer:
根据设计,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 文档,例如这个维基页面,你会发现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 省略了一些属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!