我正在尝试编写一个模拟来自Dropbox的REST服务的一些返回值的测试,该服务使用嵌套的哈希值返回数组中的数据。
我无法弄清楚如何对我的工厂进行编码,因为返回结果是一个带有内部的数组。会怎么样?
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)
答案 0 :(得分:140)
我有兴趣做同样的事情,也测试我的模型使用来自第三方API的内容散列操作。我发现通过使用factory_girl的一些内置功能,我能够干净地构建这些数据结构。
这是一个人为的例子:
factory :chicken, class:Hash do
name "Sebastian"
colors ["white", "orange"]
favorites {{
"PETC" => "http://www.petc.org"
}}
initialize_with { attributes }
end
这里的主要技巧是当你声明initialize_with时,factory_girl将不再尝试将属性分配给结果对象。在这种情况下,它似乎也跳过了db存储。因此,我们只是将已准备好的属性哈希作为内容传回,而不是构造任何复杂的东西。瞧。
似乎有必要为类指定一些值,尽管它实际上并没有被使用。这是为了防止factory_girl尝试根据工厂名称实例化一个类。我选择使用描述性的类而不是Object,但这取决于你。
当您使用其中一个哈希工厂时,您仍然可以覆盖字段:
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)
您还可以省略不必要的值。让我们想象只有路径和转速是非常必要的:
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)
答案 1 :(得分:7)
这对我有用,我可以根据需要将属性传递给哈希
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" }
答案 2 :(得分:6)
当前RSpec版本(3.0)的后续内容:
只需像往常一样定义工厂并使用FactoryGirl.attributes_for
来接收哈希而不是实例化的类。
答案 3 :(得分:4)
你可以在最新版本的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_with
将结果放在一起。这里的缺点是你需要再次写出完整的属性列表。to_create
块,以便之后不会尝试拨打array.save!
。答案 4 :(得分:-1)
我使用的是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
寻找更好的东西