Próbuję napisać test, który symuluje niektóre wartości zwracane z usługi REST Dropbox, która zwraca mi dane w tablicy, z zagnieżdżonym hashem.
Mam problem ze zrozumieniem, jak zakodować moją fabrykę, ponieważ wynikiem zwrotu jest tablica z wartością wewnątrz. Co by tu trafiło?
Factory.define :dropbox_hash do
??
end
Dane Dropbox wyglądają następująco:
["/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"}]
I chciałbym mieć taką rozmowę fabryczną w moim RSpec:
Factory.create(:dropbox_hash)
Odpowiedzi:
Byłem zainteresowany zrobieniem tego samego, również przetestowaniem mojego modelu, który działa przy użyciu skrótu treści z zewnętrznego interfejsu API. Odkryłem, że korzystając z kilku wbudowanych funkcji factory_girl byłem w stanie w przejrzysty sposób skonstruować tego rodzaju struktury danych.
Oto wymyślony przykład:
factory :chicken, class:Hash do name "Sebastian" colors ["white", "orange"] favorites {{ "PETC" => "http://www.petc.org" }} initialize_with { attributes } end
Główna sztuczka polega na tym, że kiedy deklarujesz initialize_with, factory_girl nie będzie już próbować przypisywać atrybutów do wynikowego obiektu. Wydaje się również, że w tym przypadku pomija sklep db. Więc zamiast konstruować cokolwiek skomplikowanego, po prostu przekazujemy z powrotem już przygotowany hash atrybutu jako naszą zawartość. Voila.
Wydaje się, że konieczne jest określenie jakiejś wartości dla klasy, mimo że w rzeczywistości nie jest ona używana. Ma to na celu zapobieżenie próbie utworzenia instancji klasy na podstawie nazwy fabryki przez factory_girl. Zdecydowałem się użyć klas opisowych zamiast Object, ale to zależy od Ciebie.
Nadal możesz nadpisywać pola, gdy używasz jednej z tych fabryk mieszania:
chick = FactoryGirl.build(:chicken, name:"Charles")
..Jednak jeśli masz zagnieżdżoną zawartość i chcesz zastąpić głębsze pola, będziesz musiał zwiększyć złożoność bloku inicjalizacji, aby wykonać jakieś głębokie scalanie.
W twoim przypadku używasz mieszanej tablicy i danych skrótu i wydaje się, że właściwość Path powinna być ponownie używana między częściami struktury danych. Żaden problem - znasz strukturę zawartości, więc możesz łatwo stworzyć fabrykę, która prawidłowo konstruuje wynikową tablicę. Oto, jak mogę to zrobić:
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)
Nadal możesz pomijać niepotrzebne wartości. Wyobraźmy sobie, że naprawdę potrzebne są tylko Path i 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)
źródło
favorites
bloku wieloliniowym, użyjdo..end
zamiast{{..}}
.skip_create
do fabryki, jeśli chcesz zadzwonić do „tworzenia” zamiastbuild
initialize_with
ocenia w kontekście klasy, tj. Jeśli maminitialize_with { new(attributes) }
,build :my_factory
zwróci wynikMyClass.new(attributes)
to działa dla mnie i mogę przekazywać atrybuty w razie potrzeby do skrótu
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" }
źródło
Kontynuacja dla aktualnej wersji RSpec (3.0):
Po prostu zdefiniuj swoją fabrykę w zwykły sposób i użyj funkcji,
FactoryBot.attributes_for
aby otrzymać skrót zamiast instancji klasy.źródło
Możesz to zrobić w najnowszych wersjach factory_girl, ale jest to niewygodne, ponieważ zostało zaprojektowane do tworzenia obiektów, a nie struktur danych. Oto przykład:
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
Omawiając tutaj dziwne rzeczy:
Object
tutaj, aby zapobiec jej szukaniuDropboxHash
.ignore
bloku, aby nie próbował później przypisywać ich do tablicy, na przykładarray.revision = 48
.initialize_with
. Wadą jest to, że musisz ponownie napisać pełną listę atrybutów.to_create
blok, aby nie próbowałarray.save!
później dzwonić .źródło
Użyłem OpenStruct:
factory :factory_hash, class:OpenStruct do foo "bar" si "flar" end
Edycja: przepraszam, nie działa jako skrót
W końcu używam wersji statycznej, tylko po to, aby ten hash pochodził z systemu Factory ...
factory :factory_hash, class:Hash do initialize_with { { foo "bar" si "flar" } } end
szukam czegoś lepszego
źródło