使用 RSpec 获取 API 请求的 FactoryBot 对象属性
Getting FactoryBot object attributes for API requests with RSpec
我正在设置 RSpec 请求测试,我有以下测试:
require 'rails_helper'
RSpec.describe "ClientApi::V1::ClientContexts", type: :request do
describe "POST /client_api/v1/client_contexts" do
let(:client_context) { build :client_context }
it "creates a new context" do
post "/client_api/v1/client_contexts", params: {
browser_type: client_context.browser_type,
browser_version: client_context.browser_version,
operating_system: client_context.operating_system,
operating_system_version: client_context.operating_system_version
}
expect(response).to have_http_status(200)
expect(json.keys).to contain_exactly("browser_type", "browser_version", "operating_system", "operating_system_version")
# and so on ...
end
end
end
对应的工厂是这样的:
FactoryBot.define do
factory :client_context do
browser_type { "Browser type" }
browser_version { "10.12.14-blah" }
operating_system { "Operating system" }
operating_system_version { "14.16.18-random" }
end
end
现在,显然,这一切似乎有点多余。我现在有三个地方可以指定要发送的属性。如果我想添加一个属性,我必须在所有这些地方添加。我真正想做的是发送工厂通过 POST 指定的特定属性,然后检查它们是否也被返回。
我有什么方法可以访问我在工厂中定义的属性(而且只有这些!),并在整个规范中重复使用它们?
我应该在前面加上一个警告,即从正在发出的请求中抽象出实际参数可能被视为对整体测试表现力有害。毕竟,现在您必须查看工厂以查看哪些参数被发送到服务器。
您可以简单地获取工厂定义的属性with attributes_for
:
attributes_for :client_context
如果您需要更大的灵活性,您可以可以实现一个custom strategy returns 来自工厂的属性散列,而无需创建对象,只需构建它.
创建文件spec/support/attribute_hash_strategy.rb
:
class AttributeHashStrategy
def initialize
@strategy = FactoryBot.strategy_by_name(:build).new
end
delegate :association, to: :@strategy
def result(evaluation)
evaluation.hash
end
end
这里,重要的部分是 evaluation.hash
,其中 returns 创建的对象作为 Ruby 哈希。
现在,在您的 rails_helper.rb
顶部:
require 'support/attribute_hash_strategy'
下面,在 config
块中,指定:
# this should already be there:
config.include FactoryBot::Syntax::Methods
# add this:
FactoryBot.register_strategy(:attribute_hash, AttributeHashStrategy)
现在,在规范中,您可以像这样构建哈希:
require 'rails_helper'
RSpec.describe "ClientApi::V1::ClientContexts", type: :request do
describe "POST /client_api/v1/client_contexts" do
let(:client_context) { attribute_hash :client_context }
it "creates a new context" do
client = create :client
post "/client_api/v1/client_contexts",
params: client_context
expect(response).to have_http_status(200)
end
end
end
attribute_hash
方法将是一个简单的哈希值,您可以将其作为请求参数传递。
我正在设置 RSpec 请求测试,我有以下测试:
require 'rails_helper'
RSpec.describe "ClientApi::V1::ClientContexts", type: :request do
describe "POST /client_api/v1/client_contexts" do
let(:client_context) { build :client_context }
it "creates a new context" do
post "/client_api/v1/client_contexts", params: {
browser_type: client_context.browser_type,
browser_version: client_context.browser_version,
operating_system: client_context.operating_system,
operating_system_version: client_context.operating_system_version
}
expect(response).to have_http_status(200)
expect(json.keys).to contain_exactly("browser_type", "browser_version", "operating_system", "operating_system_version")
# and so on ...
end
end
end
对应的工厂是这样的:
FactoryBot.define do
factory :client_context do
browser_type { "Browser type" }
browser_version { "10.12.14-blah" }
operating_system { "Operating system" }
operating_system_version { "14.16.18-random" }
end
end
现在,显然,这一切似乎有点多余。我现在有三个地方可以指定要发送的属性。如果我想添加一个属性,我必须在所有这些地方添加。我真正想做的是发送工厂通过 POST 指定的特定属性,然后检查它们是否也被返回。
我有什么方法可以访问我在工厂中定义的属性(而且只有这些!),并在整个规范中重复使用它们?
我应该在前面加上一个警告,即从正在发出的请求中抽象出实际参数可能被视为对整体测试表现力有害。毕竟,现在您必须查看工厂以查看哪些参数被发送到服务器。
您可以简单地获取工厂定义的属性with attributes_for
:
attributes_for :client_context
如果您需要更大的灵活性,您可以可以实现一个custom strategy returns 来自工厂的属性散列,而无需创建对象,只需构建它.
创建文件spec/support/attribute_hash_strategy.rb
:
class AttributeHashStrategy
def initialize
@strategy = FactoryBot.strategy_by_name(:build).new
end
delegate :association, to: :@strategy
def result(evaluation)
evaluation.hash
end
end
这里,重要的部分是 evaluation.hash
,其中 returns 创建的对象作为 Ruby 哈希。
现在,在您的 rails_helper.rb
顶部:
require 'support/attribute_hash_strategy'
下面,在 config
块中,指定:
# this should already be there:
config.include FactoryBot::Syntax::Methods
# add this:
FactoryBot.register_strategy(:attribute_hash, AttributeHashStrategy)
现在,在规范中,您可以像这样构建哈希:
require 'rails_helper'
RSpec.describe "ClientApi::V1::ClientContexts", type: :request do
describe "POST /client_api/v1/client_contexts" do
let(:client_context) { attribute_hash :client_context }
it "creates a new context" do
client = create :client
post "/client_api/v1/client_contexts",
params: client_context
expect(response).to have_http_status(200)
end
end
end
attribute_hash
方法将是一个简单的哈希值,您可以将其作为请求参数传递。