ruby-on-rails - 使用 Rspec 和 FactoryBot 进行 Rails 测试
问题描述
我是 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 常用方法生成这个结构。IE
factory :job_application do
field1 { "" }
field2 { "" }
end
这样我就可以按照通常的方式使用它。
解决方案
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
这些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
我们的关联。请参阅关联。
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.")
)
问问自己将这些定义为模型是否有意义。这使它们可以与普通工厂和验证等功能一起使用,您可以添加方法和所有好东西。
由于这是您在控制器中收到的数据,因此它可能会受益于验证和方法。请参阅ThoughtBot 的 ActiveModel 表单对象。
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
推荐阅读
- python - 如何从熊猫的另一列中不包含的一列中获取ID列表
- sql - 如何使用 Firebird 仅替换整个单词?
- objective-c - CSSMERR_DL_DATASTORE_DOESNOT_EXIST 尝试将私钥导入钥匙串
- java - 从字符串中删除多余的零
- oracle - 如何合并出参数嵌套表?
- python - 使用 DisplaCy 将 SpaCy 渲染文件保存为 SVG
- ios - 方法不能标记为@objc,因为参数3的类型不能在Objective-C中表示
- php - 我的代码在 laravel 辅助函数 dd() 之外不起作用
- ajax - 在ajax成功中打印返回值数组
- html - 我的电子邮件签名中的徽标图标飞到网络浏览器的最右侧,但我希望它的位置准确