Тестирование Rails с использованием Rspe c и FactoryBot - PullRequest
0 голосов
/ 16 февраля 2020

Я новичок в тестировании rails rspe c, мне нужно создать вложенную структуру данных и использовать factorybot для данных. И пока он работает для тестирования контроллера. Это не позволяет мне сделать простой Factorybot.create (: модель). Я много искал. Но, похоже, не нашел и не понял решения. Итак, структура данных, которую мне нужно создать, выглядит примерно так:

"email":"",
"name":"",
"personalDetail":{
"height":"",
"weight":"",
"color":""
}
"address":{
"street":"",
"postal_code":""
},
"experience":""
}

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

initialize_with{{
"email":"",
"name":"",
"personalDetail":{
"height":"",
"weight":"",
"color":""
}
"address":{
"street":"",
"postal_code":""
},
"experience":""
}}

работает для тестирования контроллера, но я не могу изменить значение ключа во время тестирования, например:

FactoryBot.create(:model, name:"xyz")

, а также не работает для FactoryBot.create (: модель), которая дает мне ошибку

** Api :: V1 :: someController get #index Ошибка / Ошибка: FactoryBot.create (: модель)

 NoMethodError:
   undefined method `save!' for #<Hash:0x0000563db7324060>
 # ./spec/controllers/api/v1/somecontroller_spec.rb:11:in `block (2 levels) in <main>'
 # -e:1:in `<main>' **

Итак, мой вопрос, как я могу сгенерировать эту структуру, используя обычный метод FactoryBot. то есть

factory :job_application do
    field1 { "" }
    field2 { "" }
  end 

, чтобы я мог использовать его обычным способом.

1 Ответ

1 голос
/ 16 февраля 2020

factory :job_application догадается, что вы хотите сделать объект класса JobApplication. Чтобы сделать Hash, вам нужно сделать это явно. См. Определение фабрик .

factory :job_application, class: Hash

Поскольку Hash.new не принимает набор пар ключ / значение, вам необходимо переопределить поведение инициализации по умолчанию. Я нашел самое простое, что нужно сделать - вернуть attributes фабрики. См. Пользовательская конструкция .

Они используют символьные ключи, вам нужны строковые ключи, поэтому мы используем deep_stringify_keys. Это также заботится о клонировании attributes на всякий случай.

factory :job_application, class: Hash do
  initialize_with do
    attributes.deep_stringify_keys
  end
end

Теперь вы можете добавить атрибуты обычным способом.

factory :job_application, class: Hash do
  email { "jorb@coachz.biz" }

  initialize_with do
    attributes.deep_stringify_keys
  end
end

Поскольку нет метода save, Вы можете только build эти заводы Ha sh.

# Yes
jorb = FactoryBot.build(:job_application)

# No
jorb = FactoryBot.create(:job_application)

Я часто этим занимаюсь, поэтому я построил string_hash фабрику для наследования.

factory :string_hash, class: Hash do
  initialize_with do
    attributes.deep_stringify_keys
  end
end

factory :job_application, parent: :string_hash do
  email { "jorb@coachz.biz" }
end

Если вы хотите использовать вложенные хэши, я предлагаю вам создать дополнительные фабрики и связать их вместе. Это позволяет вам легко изменять значения во вложенных хэшах.

Ассоциации по умолчанию используют create, нам нужно явно build наших ассоциаций. См. Ассоциации .

factory :address, parent: :string_hash do
  street { "Ahead St." }
  postal_code { "12345" }
end

factory :job_application, parent: :string_hash do
  association :address, strategy: :build

  email { "jorb@coachz.biz" }
  name { "Coach Z" }
end

build(:job_application,
  address: build(:address, street: "Sesame St.")
)

Спросите себя, имеет ли смысл определять их как модели . Это заставляет их работать с обычными фабриками и функциями, такими как проверка, и вы можете добавлять методы и все такое хорошее.

Поскольку эти данные вы получаете в контроллере, может быть полезно наличие проверок и методов. См. Объекты формы ActiveModel от ThoughtBot .

class JobApplication
  include ActiveModel::Model
  include ActiveModel::Validations

  attr_accessor :email, :name, :address

  validates :name, :email, presence: true
end

class Address
  include ActiveModel::Model

  attr_accessor :street, :postal_code
end

factory :address do
  street { "Ahead St." }
  postal_code { "12345" }
end

factory :job_application do
  # Can't save a Model either.
  association :address, strategy: :build

  email { "jorb@coachz.biz" }
  name { "Coach Z" }
end
...