在 FactoryBot 上指定您想要的字段

Ruf*_*eng 4 ruby rspec ruby-on-rails factory-bot

我有一个从 REST API 获取信息的对象。假设我从 API 调用 Posts,并且可以指定要提取的字段。仅举一个例子来说明它的外观:

Post.find!(id: 1, fields: [:id, :title, :description])
Run Code Online (Sandbox Code Playgroud)

这会执行 API 调用,并返回一个包含这些指定字段的 Post 对象。

为了进行测试,我使用 Factory Bot 对该 API 调用进行存根,并直接返回一个 Post 对象,其中包含它可以查询的所有可能字段。

这种方法不是最好的,因为测试总是返回所有字段和代码本身,也许我只需要几个字段而不是全部字段

所以我试图实现类似的目标(在 FactoryBot 中):

build(:post, fields: [:id,:title])并设置一个仅包含 id 和 title 的 Post 对象。

如果我这样做build(:post, fields: [:title, :created_at])并设置一个仅包含标题和created_at的Post对象。等等...

做了一些研究并尝试了一些想法,但关于如何构建这个流程的所有想法都失败了。

关于如何实现这种行为有什么想法吗?

EDIT Traits 似乎是一个不错的选择,但我必须与 API 调用保持一致,指定这些fields. 所以特质对我不起作用......

MrS*_*mek 5

假设这是您的 Post 工厂:

FactoryBot.define do
  factory :post do
    sequence(:title) { |n| "Post no. #{n}" }
    description 'Post description'
    created_at { DateTime.now }
  end
end
Run Code Online (Sandbox Code Playgroud)

当你调用它时build(:post),它将创建一个带有标题、created_at 和描述集的对象。

但是,如果您将从工厂中删除这些字段(或将它们移到特征下):

FactoryBot.define do
  factory :post do

    trait :all_fields do
      sequence(:title) { |n| "Post no. #{n}" }
      description 'Post description'
      created_at { DateTime.now }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后:

  1. 调用build(:post, title: 'Post title', description: 'Post description')将创建一个仅设置标题和描述的帖子对象(created_at将为nil)
  2. 调用build(:post, :all_fields)将创建一个 post 对象,并将设置所有字段。

编辑

我想我现在更好地理解这个问题了。假设这是您的工厂:

FactoryBot.define do
  factory :post do
    sequence(:title) { |n| "Post no. #{n}" }
    created_at { DateTime.now }
    description 'Post description'
  end
end
Run Code Online (Sandbox Code Playgroud)

将其更改为:

FactoryBot.define do
  factory :post do
    transient do
      fields []
    end

    sequence(:title) { |n| "Post no. #{n}" }
    created_at { DateTime.now }
    description 'Post description'

    after :build do |post, evaluator|
      unless evaluator.fields.empty? do
        (post.attributes.keys - evaluator.fields).each do |attribute_to_remove|
          post.send("#{attribute_to_remove}=", nil)
        end
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,你可以这样调用它:

  1. build(:post)创建包含所有字段的帖子
  2. build(:post, fields: ['description', 'title'])创建一个帖子,其中除描述和标题之外的所有内容都是nil

这个解决方案应该按预期工作,但它可能会减慢你的测试速度(而且我认为它看起来不太好:))