【问题标题】:Rails testing using Rspec and FactoryBot使用 Rspec 和 FactoryBot 进行 Rails 测试
【发布时间】:2020-02-16 13:49:27
【问题描述】:

我是 rails rspec 测试的新手,我目前需要创建嵌套数据结构并使用 factorybot 获取数据。虽然它适用于控制器测试。它不允许我做简单的 Factorybot.create(:model)。 我已经搜索了很多。但似乎没有找到或理解解决方案。 所以,我需要创建的数据结构是这样的:

"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(:model),这给了我

的错误

** Api::V1::someController 获取#index 失败/错误:FactoryBot.create(:model)

 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 

这样我就可以正常使用它了。

【问题讨论】:

  • 你想创建一个文字哈希吗?
  • 不,我知道我做错了什么,感谢您的评论。但仍然无法编写测试,我将不得不再看一些。

标签: ruby-on-rails rspec factory-bot


【解决方案1】:

factory :job_application 会猜测你想要创建一个 JobApplication 类的对象。要创建Hash,您需要明确说明。见Defining Factories

factory :job_application, class: Hash

因为Hash.new 不接受一堆键/值对,所以您需要覆盖默认的初始化行为。我发现最简单的方法是返回工厂的attributes。见Custom Construction

那些使用符号键,你想要字符串键,所以我们使用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这些Hash工厂。

# 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我们的关联。见Associations

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.")
)

问问自己define these as models 是否有意义。这使它们可以与普通工厂和验证等功能一起使用,您可以添加方法和所有好东西。

由于这是您在控制器中收到的数据,因此它可能会受益于验证和方法。见ActiveModel Form Objects by 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

【讨论】:

  • 对不起,我认为不完全理解您的建议。我的问题可能在某种程度上让你感到困惑。我想要的不是哈希,而是我以这种嵌套方式在控制器中接收数据参数。我需要建立一个在测试时会被控制器接受的工厂
  • 这应该是传递给params的哈希值。 get :create, params: build(:job_application)Something like this.(未测试)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
相关资源
最近更新 更多