Ich versuche, einen Test zu schreiben, der einige Rückgabewerte vom REST-Service von Dropbox simuliert, der mir Daten in einem Array mit einem verschachtelten Hash zurückgibt.
Ich habe Probleme herauszufinden, wie ich meine Factory codieren soll, da das Rückgabeergebnis ein Array mit einem Inneren ist. Was würde hier gehen?
Factory.define :dropbox_hash do
??
end
Dropbox-Daten sehen folgendermaßen aus:
["/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"}]
Und ich hätte gerne einen Werksaufruf wie diesen in meiner RSpec:
Factory.create(:dropbox_hash)
Antworten:
Ich war daran interessiert, dasselbe zu tun und auch ein Modell von mir zu testen, das mit einem Hash von Inhalten aus einer Drittanbieter-API arbeitet. Ich fand heraus, dass ich mithilfe einiger der integrierten Funktionen von factory_girl diese Art von Datenstrukturen sauber erstellen konnte.
Hier ist ein erfundenes Beispiel:
factory :chicken, class:Hash do name "Sebastian" colors ["white", "orange"] favorites {{ "PETC" => "http://www.petc.org" }} initialize_with { attributes } end
Der Haupttrick hier ist, dass factory_girl beim Deklarieren von initialize_with nicht mehr versucht, die Attribute dem resultierenden Objekt zuzuweisen. In diesem Fall scheint es auch den Datenbankspeicher zu überspringen. Anstatt etwas Kompliziertes zu konstruieren, geben wir einfach den bereits vorbereiteten Attribut-Hash als unseren Inhalt zurück. Voila.
Es scheint notwendig, einen Wert für die Klasse anzugeben, obwohl dieser nicht tatsächlich verwendet wird. Dies soll verhindern, dass factory_girl versucht, eine Klasse basierend auf dem Factory-Namen zu instanziieren. Ich habe mich dafür entschieden, beschreibende Klassen anstelle von Object zu verwenden, aber es liegt an Ihnen.
Sie können weiterhin Felder überschreiben, wenn Sie eine dieser Hash-Fabriken verwenden:
chick = FactoryGirl.build(:chicken, name:"Charles")
Wenn Sie jedoch verschachtelten Inhalt haben und tiefere Felder überschreiben möchten, müssen Sie die Komplexität des Initialisierungsblocks erhöhen, um eine Art Deep Merge durchzuführen.
In Ihrem Fall verwenden Sie gemischte Array- und Hash-Daten, und es scheint, dass die Path-Eigenschaft zwischen Teilen der Datenstruktur wiederverwendet werden sollte. Kein Problem - Sie kennen die Struktur des Inhalts, sodass Sie einfach eine Factory erstellen können, die das resultierende Array ordnungsgemäß erstellt. So könnte ich es machen:
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)
Sie können auch weiterhin unnötige Werte weglassen. Stellen wir uns vor, nur Pfad und Drehzahl sind wirklich notwendig:
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)
quelle
favorites
mehrzeiligen Block zu übergeben, verwenden Siedo..end
stattdessen anstelle von{{..}}
.skip_create
zur Fabrik hinzufügen , wenn Sie "erstellen" anstelle vonbuild
Ich habe das für mich zum Laufen gebracht, und ich kann Attribute nach Bedarf an den Hash übergeben
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" }
quelle
Ein Follow-up für die aktuelle RSpec-Version (3.0):
Definieren Sie einfach Ihre Factory wie gewohnt und verwenden Sie
FactoryBot.attributes_for
, um einen Hash anstelle einer instanziierten Klasse zu erhalten.quelle
Sie können dies in den neuesten Versionen von factory_girl tun, aber es ist umständlich, da es zum Erstellen von Objekten und nicht von Datenstrukturen entwickelt wurde. Hier ist ein Beispiel:
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
Ich gehe hier die seltsamen Dinge durch:
Object
hier bestanden, um zu verhindern, dass sie gesucht wirdDropboxHash
.ignore
Blocks ignorieren , damit nicht versucht wird, sie anschließend dem Array zuzuweisenarray.revision = 48
.initialize_with
. Der Nachteil hierbei ist, dass Sie die vollständige Attributliste erneut ausschreiben müssen.to_create
Block angeben, damit er nicht versucht,array.save!
danach aufzurufen .quelle
Ich habe OpenStruct verwendet:
factory :factory_hash, class:OpenStruct do foo "bar" si "flar" end
Edit: sorry, funktioniert nicht als Hash
Ich benutze endlich eine statische Version, nur um zu verhindern, dass der Hash vom Factory-System kommt ...
factory :factory_hash, class:Hash do initialize_with { { foo "bar" si "flar" } } end
auf der Suche nach etwas Besserem
quelle