web-dev-qa-db-fra.com

Comment définir un tableau / hachage dans Factory Girl?

J'essaie d'écrire un test qui simule certaines valeurs de retour du service REST de Dropbox qui me renvoie des données dans un tableau, avec un hachage imbriqué.

J'ai du mal à comprendre comment coder mon usine car le résultat de retour est un tableau avec un a à l'intérieur. Qu'est-ce qui irait ici?

Factory.define :dropbox_hash do
 ??
end

Les données de Dropbox ressemblent à ceci:

 ["/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"}] 

Et je voudrais un appel d'usine comme celui-ci dans mon RSpec:

Factory.create(:dropbox_hash)
77
Doug

J'étais intéressé à faire la même chose, également pour tester un de mes modèles qui fonctionne en utilisant un hachage de contenu à partir d'une API tierce. J'ai découvert qu'en utilisant quelques-unes des fonctionnalités intégrées de factory_girl, j'ai pu construire proprement ce type de structures de données.

Voici un exemple artificiel:

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

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

    initialize_with { attributes } 
  end

L'astuce principale ici est que lorsque vous déclarez initialize_with, factory_girl ne tentera plus d'attribuer les attributs à l'objet résultant. Il semble également ignorer le magasin db dans ce cas. Ainsi, au lieu de construire quelque chose de compliqué, nous renvoyons simplement le hachage d'attribut déjà préparé comme notre contenu. Voila.

Il semble nécessaire de spécifier une valeur pour la classe, bien qu'elle ne soit pas réellement utilisée. C'est pour empêcher factory_girl d'essayer d'instancier une classe basée sur le nom de l'usine. J'ai choisi d'utiliser des classes descriptives plutôt que Object, mais c'est à vous.

Vous pouvez toujours remplacer les champs lorsque vous utilisez l'une de ces usines de hachage:

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

.. cependant, si vous avez du contenu imbriqué et que vous souhaitez remplacer des champs plus profonds, vous devrez augmenter la complexité du bloc d'initialisation pour effectuer une sorte de fusion profonde.

Dans votre cas, vous utilisez des données mixtes de tableau et de hachage, et il semble que la propriété Path devrait être réutilisée entre des parties de la structure de données. Pas de problème - vous connaissez la structure du contenu, vous pouvez donc facilement créer une fabrique qui construit correctement le tableau résultant. Voici comment je pourrais le faire:

  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)

Vous êtes également toujours libre d'omettre des valeurs inutiles. Imaginons que seuls Path et rev soient vraiment nécessaires:

  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)
143
doublemarked

a obtenu ce travail pour moi, et je peux passer des attributs au besoin dans le hachage

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" }
8
jethroo

Un suivi pour la version actuelle de RSpec (3.0):

Définissez simplement votre usine comme d'habitude et utilisez FactoryBot.attributes_for pour recevoir un hachage au lieu d'une classe instanciée.

7
milgner

Vous pouvez le faire dans les dernières versions de factory_girl, mais c'est gênant car il est conçu pour construire des objets et non des structures de données. Voici un exemple:

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

Revenant sur les trucs bizarres ici:

  • Chaque usine a besoin d'une classe de build valide même si elle n'est pas utilisée, j'ai donc passé Object ici pour l'empêcher de rechercher DropboxHash.
  • Vous devez ignorer tous les attributs à l'aide d'un bloc ignore afin qu'il n'essaye pas de les affecter au tableau par la suite, comme array.revision = 48.
  • Vous pouvez lui dire comment assembler votre résultat en utilisant initialize_with. L'inconvénient ici est que vous devez réécrire la liste complète des attributs.
  • Vous devez fournir un to_create bloquer pour ne pas essayer d'appeler array.save! ensuite.
5
Joe Ferris

J'ai utilisé OpenStruct:

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

Modifier: désolé, ne fonctionne pas comme un hachage

J'utilise enfin une version statique, juste pour garder ce hachage provenant du système Factory ...

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

chercher quelque chose de mieux

0
jobwat