2012-04-05 9 views
64

Próbuję napisać test symulujący niektóre wartości zwracane z usługi REST usługi Dropbox, która daje mi dane z powrotem w tablicy z zagnieżdżonym hashiem.Jak zdefiniować tablicę/hasz w Factory Girl?

Mam problem z ustaleniem sposobu zakodowania mojej fabryki, ponieważ wynik zwracany jest tablicą zawierającą. Co by tu było?

Factory.define :dropbox_hash do 
?? 
end 

Dropbox danych wygląda 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 połączenia fabrycznego jak to w moim RSpec:

Factory.create(:dropbox_hash) 
+0

Czy naprawdę potrzebny jest fabrycznie do tego? Dlaczego po prostu nie zdefiniować metody, która zwraca symulowaną odpowiedź? – zetetic

+0

Tak właśnie zrobiłem. Ale myślałem, że celem Fabryk jest izolowanie tych rzeczy. Wciąż jestem ciekawy - wydaje mi się, że klasy są Hash i Array, i to powinno działać, jeśli mogę po prostu uzyskać właściwą składnię. – Doug

+0

Użyłem ich tylko do generowania instancji modelu ActiveRecord. FactoryGirl ma zastąpić urządzenia. Możesz rzucić okiem na pomocnicze metody RSpec: https://www.relishapp.com/rspec/rspec-core/v/2-9/docs/helper-methods – zetetic

Odpowiedz

125

Byłem zainteresowany robieniem tego samego, także przetestować model kopalni, który działa przy użyciu skrótu treści z API innej firmy. Zauważyłem, że używając kilku wbudowanych funkcji factory_girl udało mi się oczyścić konstrukcje tego typu danych.

Oto zmyślony przykład:

factory :chicken, class:Hash do 
    name "Sebastian" 
    colors ["white", "orange"] 

    favorites {{ 
     "PETC" => "http://www.petc.org" 
    }} 

    initialize_with { attributes } 
    end 

Głównym Sztuką jest to, że kiedy zadeklarować initialize_with, factory_girl nie będzie próbować przypisać atrybuty do powstałego obiektu. Wydaje się także, że w tym przypadku pomija magazyn db. Tak więc, zamiast tworzyć coś skomplikowanego, po prostu przekazujemy już przygotowany skrót hasłowy jako naszą treść. Voila.

Wydaje się, że konieczne jest podanie pewnej wartości dla klasy, mimo że nie jest ona faktycznie używana. Ma to na celu uniemożliwienie factory_girl próby utworzenia instancji klasy na podstawie nazwy fabryki. Postanowiłem użyć klas opisowych zamiast Object, ale to zależy od ciebie.

Nadal jesteś w stanie przesłonić pól podczas korzystania z tych fabryk hash:

chick = FactoryGirl.build(:chicken, name:"Charles") 

..however, jeśli zagnieżdżony treści i chcą zastąpić głębsze pól trzeba będzie zwiększyć złożoność bloku inicjalizacyjnego do pewnego rodzaju głębokiego scalenia.

W twoim przypadku używasz mieszanych danych tablicowych i mieszających, i wygląda na to, że właściwość Path powinna zostać ponownie wykorzystana między częściami struktury danych. Nie ma problemu - znasz strukturę treści, dzięki czemu możesz łatwo utworzyć fabrykę, która poprawnie tworzy 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 również pominąć niepotrzebne wartości. Wyobraźmy sobie tylko ścieżka i rev są naprawdę konieczne:

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) 
+0

To jest świetne rozwiązanie. Działa nawet z dziedziczeniem fabryk. –

4

Można to zrobić w najnowszych wersjach factory_girl, ale jest niezręczny, ponieważ jest przeznaczony do budowania 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 

Przejście dziwne rzeczy tutaj:

  • Każda fabryka potrzebuje ważnej klasy kompilacji nawet, jeśli nie jest używany, więc zdałem Object tutaj, aby zapobiec jej szuka DropboxHash.
  • Należy zignorować wszystkie atrybuty przy użyciu bloku ignore, aby później nie próbował przypisać ich do tablicy, na przykład array.revision = 48.
  • Możesz powiedzieć, jak połączyć swój wynik, używając initialize_with. Wadą jest to, że musisz ponownie wypisać pełną listę atrybutów.
  • Musisz podać pusty blok to_create, aby później nie próbował wywoływać numeru array.save!.
-1

użyłem OpenStruct:

factory :factory_hash, class:OpenStruct do 
    foo "bar" 
    si "flar" 
end 

Edit: Niestety, nie działa jako Hash

I wreszcie wykorzystać wersję statyczną, po prostu aby zachować hasz pochodzący z systemu Factory ...

factory :factory_hash, class:Hash do 
    initialize_with { { 
    foo "bar" 
    si "flar" 
    } } 
end 

szukasz czegoś lepszego

6

nawiązanie do obecnego RSpec wersji (3.0):

wystarczy zdefiniować swoją fabrykę jak zwykle i wykorzystać FactoryGirl.attributes_for otrzymywać hash zamiast instancja klasy.

4

dostałem tej pracy dla mnie i mogę przekazać atrybuty jako potrzebne do mieszania

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" } 
+1

Ma to również dodatkową zaletę polegającą na zezwalaniu kluczom na ciągi. – crftr

Powiązane problemy