Как определить массив / хэш в Factory Girl?

Я пытаюсь написать тест, который имитирует некоторые возвращаемые значения из службы REST Dropbox, которая возвращает мне данные в массиве с вложенным хешем.

У меня возникают проблемы с выяснением того, как закодировать мою фабрику, поскольку возвращаемый результат - массив с внутренним значением. Что пойдет сюда?

<code>Factory.define :dropbox_hash do
 ??
end
</code>

Данные Dropbox выглядят так:

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

И мне нравится заводской вызов в RSpec:

<code>Factory.create(:dropbox_hash)
</code>
 zetetic06 апр. 2012 г., 20:19
Я использовал их только для генерации экземпляров модели ActiveRecord. FactoryGirl предназначена для замены светильников. Вы можете взглянуть на вспомогательные методы RSpec:relishapp.com/rspec/rspec-core/v/2-9/docs/helper-methods
 Doug06 апр. 2012 г., 18:41
Это то, что я в итоге сделал. Но я думал, что целью Фабрики было изолировать этот материал. Мне все еще любопытно - кажется, что Hash и Array являются классами, и это должно работать, если я могу просто получить правильный синтаксис.
 zetetic06 апр. 2012 г., 05:22
Вам действительно нужен завод для этого? Почему бы просто не определить метод, который возвращает смоделированный ответ?

Ответы на вопрос(5)

Продолжение для текущей версии RSpec (3.0):

Просто определите свою фабрику как обычно и используйтеFactoryGirl.attributes_for получить хеш вместо экземпляра класса.

 20 авг. 2018 г., 21:25
Драгоценный камень был переименован в FactoryBot. Новое место для этой документацииrubydoc.info/github/thoughtbot/factory_bot/FactoryBot/Syntax/…

получил это работает для меня, и я могу передавать атрибуты по мере необходимости в хэш

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" }
 22 дек. 2016 г., 08:38
Это также даст дополнительное преимущество, позволяя ключам быть строками.

Вы можете сделать это в последних версиях 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

Рассмотрим странные вещи здесь:

Every factory needs a valid build class even if it's not used, so I passed Object here to prevent it from looking for DropboxHash. You need to ignore all the attributes using an ignore block so that it doesn't try to assign them to the array afterwards, like array.revision = 48. You can tell it how to put your result together using initialize_with. The downside here is that you need to write out the full attribute list again. You need to provide an empty to_create block so that it doesn't try to call array.save! afterwards.

Я использовал OpenStruct:

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

Редактировать: извините, не работает как хэш

Наконец, я использую статическую версию, просто чтобы сохранить этот хэш, исходящий из системы Factory ...

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

в поисках чего-то лучшего

Решение Вопроса

Мне было интересно сделать то же самое, а также протестировать мою модель, которая работает с использованием хэша контента от стороннего 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 больше не будет пытаться присвоить атрибуты результирующему объекту. Похоже, что в этом случае пропустить магазин БД. Таким образом, вместо создания чего-либо сложного, мы просто передаем обратно уже подготовленный хэш атрибута в качестве нашего содержимого. Вуаля.

Кажется необходимым указать какое-то значение для класса, несмотря на то, что оно на самом деле не используется. Это необходимо для того, чтобы 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)

Вы также можете свободно опускать ненужные значения. Давайте представим, что только Path и 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)
 24 янв. 2014 г., 19:27
Это отличное решение. Это даже работает с фабриками & apos; наследование.
 18 авг. 2018 г., 17:40
Спасибо тебе за это. Чтобы передать Rubocop Linter вfavorites использование многострочного блокаdo..end вместо{{..}}.
 28 мая 2018 г., 16:08
Это работает для меня, чтобы создать / построить, но это терпит неудачу lint: FacoryGirl.lint

Ваш ответ на вопрос