本文介绍了FactoryGirl:为什么attributes_for会省略一些属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在控制器测试中使用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周围包装了一个辅助方法,该方法去除了idcreated_atupdated_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会省略一些属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 04:19