使用 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 方法将是一个简单的哈希值,您可以将其作为请求参数传递。