Ruby on rails 我如何重置工厂女孩序列?

Ruby on rails 我如何重置工厂女孩序列?,ruby-on-rails,ruby,factory-bot,Ruby On Rails,Ruby,Factory Bot,如果我有一个项目工厂 Factory.define :project do |p| p.sequence(:title) { |n| "project #{n} title" } p.sequence(:subtitle) { |n| "project #{n} subtitle" } p.sequence(:image) { |n| "../images/content/projects/#{n}.jpg"

如果我有一个项目工厂

Factory.define :project do |p|
  p.sequence(:title)    { |n| "project #{n} title"                  }
  p.sequence(:subtitle) { |n| "project #{n} subtitle"               }
  p.sequence(:image)    { |n| "../images/content/projects/#{n}.jpg" }
  p.sequence(:date)     { |n| n.weeks.ago.to_date                   }
end
我正在创建项目的实例

Factory.build :project
Factory.build :project
此时,下次执行Factory.build(:project)时,我将收到一个项目实例,其标题设置为“project3 title”,依此类推。不足为奇

现在我想在这个范围内重置计数器。比如:

Factory.build :project #=> Project 3
Factory.reset :project #=> project factory counter gets reseted
Factory.build :project #=> A new instance of project 1
实现这一目标的最佳方式是什么

我目前正在使用以下版本:

工厂女孩(1.3.1) 工厂女孩轨道(1.0)

提前感谢,,
致以最诚挚的问候。

没有重置序列的内置方法,请参阅此处的源代码:

然而,有些人已经在中黑客/猴子修补了此功能。下面是一个例子:

大家好, 在对源代码进行跟踪之后,我终于找到了一个解决方案。如果您使用的是factory_girl 1.3.2(这是我撰写本文时的最新版本),则可以将以下代码添加到factories.rb文件的顶部:

class Factory  
  def self.reset_sequences
    Factory.factories.each do |name, factory|
      factory.sequences.each do |name, sequence|
        sequence.reset
      end
    end
  end

  def sequences
    @sequences
  end

  def sequence(name, &block)
    s = Sequence.new(&block)

    @sequences ||= {}
    @sequences[name] = s

    add_attribute(name) { s.next }
  end

  def reset_sequence(name)
    @sequences[name].reset
  end

  class Sequence
    def reset
      @value = 0
    end
  end
end
然后,在Cucumber的env.rb中,只需添加:

After do
  Factory.reset_sequences
end
我假设,如果您在rspec测试中遇到相同的问题,您可以在每个方法之后使用rspec

目前,该方法仅考虑工厂内定义的序列,例如:

Factory.define :specialty do |f|
  f.sequence(:title) { |n| "Test Specialty #{n}"}
  f.sequence(:permalink) { |n| "permalink#{n}" }
end
我还没有编写代码来处理:Factory.sequence

希望这能帮助所有其他沮丧的人,他们不明白为什么世界上的工厂女孩还没有提供这些。也许我会分叉github项目,并提交一个带有此修复程序的pull请求,因为它不会改变它们的任何内部功能


-Andrew

根据ThoughBot,需要重置测试之间的顺序是一种反模式

要汇总

如果你有这样的东西:

FactoryGirl.define do
  factory :category do
    sequence(:name) {|n| "Category #{n}" }
  end
end
Scenario: Create a post under a category
   Given a category exists with a name of "Category 1"
   And I am signed in as an admin
   When I go to create a new post
   And I select "Category 1" from "Categories"
   And I press "Create"
   And I go to view all posts
   Then I should see a post with the category "Category 1"
class FGCustomSequence
  def initialize(max)
    @marker, @max = 1, max
  end
  def next
    @marker = (@marker >= @max ? 1 : (@marker + 1))
  end
  def peek
    @marker.to_s
  end
end

FactoryGirl.define do
  factory :image do
    sequence(:picture, FGCustomSequence.new(8)) { |n| "image#{n.to_s}.png" }
  end
end
您的测试应该如下所示:

FactoryGirl.define do
  factory :category do
    sequence(:name) {|n| "Category #{n}" }
  end
end
Scenario: Create a post under a category
   Given a category exists with a name of "Category 1"
   And I am signed in as an admin
   When I go to create a new post
   And I select "Category 1" from "Categories"
   And I press "Create"
   And I go to view all posts
   Then I should see a post with the category "Category 1"
class FGCustomSequence
  def initialize(max)
    @marker, @max = 1, max
  end
  def next
    @marker = (@marker >= @max ? 1 : (@marker + 1))
  end
  def peek
    @marker.to_s
  end
end

FactoryGirl.define do
  factory :image do
    sequence(:picture, FGCustomSequence.new(8)) { |n| "image#{n.to_s}.png" }
  end
end
不是这个:

Scenario: Create a post under a category
  Given a category exists
  And I am signed in as an admin
  When I go to create a new post
  And I select "Category 1" from "Categories"
  And I press "Create"
  And I go to view all posts
  Then I should see a post with the category "Category 1"

只需调用FactoryGirl.reload在您的前/后回调中。这在FactoryGirl代码库中定义为:

module FactoryGirl
  def self.reload
    self.factories.clear
    self.sequences.clear
    self.traits.clear
    self.find_definitions
  end
end

出于某些原因,调用FactoryGirl.sequences.clear是不够的。执行完全重新加载可能会有一些开销,但是当我尝试使用/不使用回调时,我的测试在任何一种方式下都需要大约30秒的时间。因此,开销不足以影响我的工作流程。

对于谷歌用户:无需进一步扩展,只需执行
FactoryGirl.reload

FactoryGirl.create :user
#=> User id: 1, name: "user_1"
FactoryGirl.create :user
#=> User id: 2, name: "user_2"

DatabaseCleaner.clean_with :truncation #wiping out database with truncation
FactoryGirl.reload

FactoryGirl.create :user
#=> User id: 1, name: "user_1"
为我工作

* factory_girl (4.3.0)
* factory_girl_rails (4.3.0)

要重置特定序列,您可以尝试

# spec/factories/schedule_positions.rb
FactoryGirl.define do
  sequence :position do |n| 
    n
  end

  factory :schedule_position do
    position
    position_date Date.today
    ...
  end
end

# spec/models/schedule_position.rb
require 'spec_helper'

describe SchedulePosition do
  describe "Reposition" do
    before(:each) do
      nullify_position
      FactoryGirl.create_list(:schedule_position, 10)
    end
  end

  protected

  def nullify_position
    position = FactoryGirl.sequences.find(:position)
    position.instance_variable_set :@value, FactoryGirl::Sequence::EnumeratorAdapter.new(1)
  end
end

Had必须确保序列从1到8,并重新启动到1,依此类推。实施方式如下:

FactoryGirl.define do
  factory :category do
    sequence(:name) {|n| "Category #{n}" }
  end
end
Scenario: Create a post under a category
   Given a category exists with a name of "Category 1"
   And I am signed in as an admin
   When I go to create a new post
   And I select "Category 1" from "Categories"
   And I press "Create"
   And I go to view all posts
   Then I should see a post with the category "Category 1"
class FGCustomSequence
  def initialize(max)
    @marker, @max = 1, max
  end
  def next
    @marker = (@marker >= @max ? 1 : (@marker + 1))
  end
  def peek
    @marker.to_s
  end
end

FactoryGirl.define do
  factory :image do
    sequence(:picture, FGCustomSequence.new(8)) { |n| "image#{n.to_s}.png" }
  end
end

上面说“该值只需要支持
#next
方法。”但要让CustomSequence对象通过它,还需要支持
#peek
方法。最后,我不知道这会持续多久,因为它有点侵入FactoryGirl内部,当他们做出更改时,这可能无法正常工作

如果您使用Cucumber,您可以将其添加到步骤定义中:

Given(/^I reload FactoryGirl/) do
  FactoryGirl.reload
end

然后在需要的时候打电话给它。

这已经很老了,但它是谷歌搜索相关关键字的最佳结果。 对于任何一个在这上面绊倒的人

有一个名为
sequence\u by\u name
的类方法,可以按名称获取序列,然后可以调用
rewind
,它将重置为1

FactoryBot.sequence_by_name(:order).rewind
或者,如果要重置所有

FactoryBot.rewind_sequences

您好,我一直在隐藏他们的来源,还发现了您链接的帖子。我还没弄明白怎么解决我的问题。Factory.sequences的行为[显然]很奇怪。Factory.build(:project)#=>project1 Factory.build(:project)#=>project2 Factory.sequences.delete(:project)Factory.build(:project)#=>project3仍在试图找出原因。该序列在此处为您提供一个受保护的唯一ID,而不是对象的计数。这种行为正是你应该期待的。这些用于确保每次从工厂创建实例时都会生成唯一的名称。这正是我试图重置的内容:)我发现重置测试之间的序列非常有用,因此我现在知道每个测试的预期内容,并且我的测试更具声明性。您好,任何人都可以告诉我在哪里可以添加factories.rb文件。在features文件或spec文件中。请参阅下面@brandon的帖子,以获得更高投票率的答案,并且不需要猴子补丁。大家好,可以告诉我您在哪里添加了factories.rb文件。在功能文件或规范文件中。谢谢,它可以工作。我在spec->support->reset.rb文件中添加了此代码,并在do FactoryGirl.reload end之后添加了
此代码。在4.5.0版的env.rb文件中,我使用
FactoryGirl.configuration.sequences[:iterator]实现了此操作。实例变量获取(@value”)。实例变量集(@value),1)
(其中:iterator是序列的名称)。请注意,这只适用于全局序列。可能是旧的,但这完全救了我现在!谢谢。这可以简化为
序列(:picture,0){n|“image{n%8+1}.png}