前提是我有一个项目工厂
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)
提前致谢, 最好的问候。
答案 0 :(得分:43)
只需在回调之前/之后调用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秒才能运行。因此,开销不足以影响我的工作流程。
答案 1 :(得分:11)
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项目并使用此修复程序提交拉取请求,因为它不会更改任何内部功能。
-Andrew
答案 2 :(得分:9)
对于谷歌搜索用户:无需进一步扩展,只需执行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)
答案 3 :(得分:6)
根据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"
答案 4 :(得分:2)
必须确保序列从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
doc表示"该值只需支持#next
方法。"但是为了让你继续使用CustomSequence对象,它也需要支持#peek
方法。最后,我不知道这会有多长时间,因为它会侵入FactoryGirl内部,当他们做出改变时,这可能无法正常工作
答案 5 :(得分:2)
这已经很老了,但这是google在相关关键字上的最佳搜索结果。 对于任何绊脚石。
有一个名为sequence_by_name
的类方法可以按名称获取序列,然后可以调用rewind
并将其重置为1。
FactoryBot.sequence_by_name(:order).rewind
或者如果您想全部重设。
FactoryBot.rewind_sequences
答案 6 :(得分:1)
没有内置的重置序列的方法,请参阅此处的源代码:
http://github.com/thoughtbot/factory_girl/blob/master/lib/factory_girl/sequence.rb
然而,有些人已经黑客攻击/修补了这个功能。这是一个例子:
http://www.pmamediagroup.com/2009/05/smarter-sequencing-in-factory-girl/
答案 7 :(得分: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
答案 8 :(得分:0)
如果您使用的是Cucumber,可以将其添加到步骤定义中:
Given(/^I reload FactoryGirl/) do
FactoryGirl.reload
end
然后在需要时调用它。