简体   繁体   English

使用 Rspec 和 FactoryBot 进行 Rails 测试

[英]Rails testing using Rspec and FactoryBot

I am new to rails rspec testing, I currently need to created nested data structure and using factorybot for data.我是 rails rspec 测试的新手,我目前需要创建嵌套数据结构并使用 factorybot 数据。 And while it works for controller testing.虽然它适用于控制器测试。 Its not letting me do simple Factorybot.create(:model).它不允许我做简单的 Factorybot.create(:model)。 I have searched a lot.我已经搜索了很多。 But didn't seem to find or understand a solution.但似乎没有找到或理解解决方案。 So, data structure i need to create is something like:所以,我需要创建的数据结构是这样的:

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

(**note. this not association related, data in controller is received in such a way. There is no relationship involved) while i am currently achieving this structure using (**注意。这与关联无关,控制器中的数据以这种方式接收。不涉及任何关系)而我目前正在使用

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

its works for controller testing but it i'm not able to change key value while testing like:它适用于控制器测试,但我无法在测试时更改键值,例如:

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

, and also is not working for FactoryBot.create(:model), which is giving me error of ,并且也不适用于 FactoryBot.create(:model),这给了我错误

** Api::V1::someController get #index Failure/Error: FactoryBot.create(:model) ** Api::V1::someController get #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>' **

So, my question is how can i generate this structure using FactoryBot usual method.所以,我的问题是如何使用 FactoryBot 通常的方法生成这个结构。 ie IE

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

so that i can use it usual way.这样我就可以正常使用它了。

factory :job_application will guess that you want to make an object of the class JobApplication . factory :job_application会猜测您想要创建JobApplication类的对象。 To make a Hash you need to make it explicit.要制作Hash您需要使其明确。 See Defining Factories .请参阅定义工厂

factory :job_application, class: Hash

Because Hash.new does not take a bunch of key/value pairs, you need to override the default initialization behavior.因为Hash.new不需要一堆键/值对,所以你需要覆盖默认的初始化行为。 I've found the simplest thing to do is to return the attributes of the factory.我发现最简单的方法是返回工厂的attributes See Custom Construction .请参阅自定义构造

Those use symbol keys, you want string keys, so we use deep_stringify_keys .那些使用符号键,你需要字符串键,所以我们使用deep_stringify_keys This also takes care of cloning attributes just in case.以防万一,这也会处理克隆attributes

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

Now you can add attributes in the normal way.现在您可以以正常方式添加属性。

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

  initialize_with do
    attributes.deep_stringify_keys
  end
end

Because there is no save method, you can only build these Hash factories.因为没有save方法,所以只能build这些Hash工厂。

# Yes
jorb = FactoryBot.build(:job_application)

# No
jorb = FactoryBot.create(:job_application)

I find myself doing this a lot, so I've built a string_hash factory to inherit from.我发现自己string_hash这样做,所以我建立了一个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

If you want nested hashes, I suggest you make additional factories and associate them together.如果您想要嵌套哈希,我建议您制作额外的工厂并将它们关联在一起。 This allows you to easily change the values in the nested hashes.这使您可以轻松更改嵌套散列中的值。

Associations default to using create , we need to explicitly build our associations.关联默认使用create ,我们需要明确地build我们的关联。 See 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.")
)

Do ask yourself whether it makes sense to define these as models .一定要问问自己将这些定义为模型是否有意义。 This makes them work with normal factories and features like validation and you can add methods and all that good stuff.这使它们可以与普通工厂和验证等功能一起使用,并且您可以添加方法和所有好东西。

Since this is data you receive in a controller it might benefit from having validations and methods.由于这是您在控制器中收到的数据,因此它可能会受益于验证和方法。 See ActiveModel Form Objects by ThoughtBot .请参阅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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM