如何重置factory_girl序列?

只要我有一个项目工厂

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)时,我将收到一个Project的实例,其标题设置为“project 3 title”,依此类推。 不奇怪。

现在说我希望在这个范围内重置我的计数器。 就像是:

 Factory.build :project #=> Project 3 Factory.reset :project #=> project factory counter gets reseted Factory.build :project #=> A new instance of project 1 

实现这一目标的最佳方法是什么?

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

factory_girl(1.3.1)factory_girl_rails(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测试中遇到同样的问题,你可以在每个方法之后使用rspecs。

目前,这种方法只考虑工厂内定义的序列,例如:

 Factory.define :specialty do |f| f.sequence(:title) { |n| "Test Specialty #{n}"} f.sequence(:permalink) { |n| "permalink#{n}" } end 

我还没有编写代码来处理:Factory.sequence …

希望这有助于所有其他沮丧的人在那里谁不明白为什么在世界工厂女孩不提供这个。 也许我会分叉github项目并提交一个带有此修复的pull请求,因为它不会更改任何内部function。

-安德鲁

只需在回调之前/之后调用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) 

https://stackoverflow.com/a/16048658

根据YetBot Here ,需要在测试之间重置序列是一种反模式。

总结一下

如果您有这样的事情:

 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" 

不是这个:

 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" 

必须确保序列从1到8并重新启动到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内部,当他们做出改变时,这可能无法正常工作

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

http://github.com/thoughtbot/factory_girl/blob/master/lib/factory_girl/sequence.rb

但是,有些人已经黑客/猴子修补了这个function。这是一个例子:

http://www.pmamediagroup.com/2009/05/smarter-sequencing-in-factory-girl/

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

 # 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 

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

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

然后在需要时调用它。