Ruby on rails 3 如何在factory_bot中定义数组/哈希?
我试图编写一个测试,模拟Dropbox的REST服务返回的一些值,该服务使用嵌套哈希返回数组中的数据 由于返回的结果是一个内部带有has的数组,因此我很难理解如何对工厂进行编码。这里会有什么Ruby on rails 3 如何在factory_bot中定义数组/哈希?,ruby-on-rails-3,rspec,factory-bot,Ruby On Rails 3,Rspec,Factory Bot,我试图编写一个测试,模拟Dropbox的REST服务返回的一些值,该服务使用嵌套哈希返回数组中的数据 由于返回的结果是一个内部带有has的数组,因此我很难理解如何对工厂进行编码。这里会有什么 Factory.define :dropbox_hash do ?? end Dropbox数据如下所示: ["/home", {"revision"=>48, "rev"=>"30054214dc", "thumb_exists"=>false, "bytes"=>0, "m
Factory.define :dropbox_hash do
??
end
Dropbox数据如下所示:
["/home", {"revision"=>48, "rev"=>"30054214dc", "thumb_exists"=>false, "bytes"=>0, "modified"=>"Thu, 29 Dec 2011 01:53:26 +0000", "path"=>"/Home", "is_dir"=>true, "icon"=>"folder_app", "root"=>"app_folder", "size"=>"0 bytes"}]
我希望在我的RSpec中有这样的工厂电话:
Factory.create(:dropbox_hash)
在最新版本的factory_girl中可以做到这一点,但这很尴尬,因为它是为构建对象而设计的,而不是数据结构。下面是一个例子:
FactoryGirl.define do
factory :dropbox_hash, :class => 'Object' do
ignore do
url { "/home" }
revision { 48 }
rev { "30054214dc" }
# more attributes
end
initialize_with { [url, { "revision" => revision, "rev" => rev, ... }] }
to_create {}
end
end
回顾一下这里奇怪的东西:
- 每个工厂都需要一个有效的构建类,即使它没有被使用,所以我在这里传递了
,以防止它查找Object
DropboxHash
- 您需要使用
块忽略所有属性,这样它就不会在以后尝试将它们分配给数组,比如ignore
array.revision=48
- 您可以使用
告诉它如何将结果组合在一起。这里的缺点是您需要再次写出完整的属性列表initialize\u with
- 您需要提供一个空的
来创建
块,这样它就不会试图调用
array.save代码>之后
factory :chicken, class:Hash do
name "Sebastian"
colors ["white", "orange"]
favorites {{
"PETC" => "http://www.petc.org"
}}
initialize_with { attributes }
end
这里的主要技巧是,当您声明initialize_with时,factory_女孩将不再尝试将属性分配给结果对象。在这种情况下,它似乎也跳过了db存储。因此,我们不需要构建任何复杂的内容,只需将已经准备好的属性哈希作为内容传回。瞧
尽管没有实际使用该类,但似乎有必要为该类指定一些值。这是为了防止工厂试图基于工厂名称实例化类。我选择使用描述性类而不是对象,但这取决于您
当您使用以下哈希工厂之一时,仍然可以覆盖字段:
chick = FactoryGirl.build(:chicken, name:"Charles")
..但是,如果您有嵌套的内容,并且希望覆盖更深的字段,则需要增加初始化块的复杂性以进行某种深度合并
在您的例子中,您使用的是一些混合数组和散列数据,似乎应该在数据结构的各个部分之间重用Path属性。没问题-您知道内容的结构,因此可以轻松创建一个工厂来正确构造结果数组。我可以这样做:
factory :dropbox_hash, class:Array do
path "/home"
revision 48
rev "30054214dc"
thumb_exists false
bytes 0
modified { 3.days.ago }
is_dir true
icon "folder_app"
root "app_folder"
size "0 bytes"
initialize_with { [ attributes[:path], attributes ] }
end
FactoryGirl.build(:dropbox_hash, path:"/Chickens", is_dir:false)
您还可以随意省略不必要的值。让我们想象一下,只有Path和rev是真正必要的:
factory :dropbox_hash, class:Array do
path "/home"
rev "30054214dc"
initialize_with { [ attributes[:path], attributes ] }
end
FactoryGirl.build(:dropbox_hash, path:"/Chickens", revision:99, modified:Time.now)
我使用了OpenStruct:
factory :factory_hash, class:OpenStruct do
foo "bar"
si "flar"
end
编辑:抱歉,不能作为哈希值使用
我最后使用了一个静态版本,只是为了保持来自工厂系统的哈希
factory :factory_hash, class:Hash do
initialize_with { {
foo "bar"
si "flar"
} }
end
寻找更好的当前RSpec版本(3.0)的后续版本:
只需像往常一样定义工厂,并使用它来接收散列而不是实例化的类。让这项工作对我起作用,我可以根据需要将属性传递到散列中
factory :some_name, class:Hash do
defaults = {
foo: "bar",
baz: "baff"
}
initialize_with{ defaults.merge(attributes) }
end
> build :some_name, foo: "foobar" #will give you
> { foo: "foobar", baz: "baff" }
你真的需要一个工厂吗?为什么不定义一个返回模拟响应的方法呢?我最后就是这么做的。但我认为工厂的目的是隔离这些东西。我仍然很好奇-看起来Hash和Array是类,如果我能得到正确的语法,这应该可以工作。我只在生成ActiveRecord模型实例时使用过它们。FactoryGirl打算更换固定装置。您可以看看RSpec的helper方法:这是一个很好的解决方案。它甚至可以与工厂的继承一起工作。这对我创建/构建来说是可行的,但是它失败了。要在
收藏夹中传递Rubocop linter
多行块,请使用do..end
而不是{..}
。如果要调用“创建”而不是build
,可以将跳过创建
添加到工厂。我发现我可以初始化任何自定义类,initialize\u with
在类上下文中求值,也就是说,如果我有initialize\u with{new(attributes)}
,build:my\u工厂
将返回MyClass.new(attributes)的结果
这还有一个额外的好处,即允许键为字符串。缺点是每次创建对象时都要修改单个对象,而不是新对象。看看散列的对象id,gem被重命名为FactoryBot。该文档的新位置是