Как я могу reset последовательность factory_girl?
Если у меня есть проект factory
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" и т.д. Не удивительно.
Теперь скажите, что я хочу reset мой счетчик в этой области. Что-то вроде:
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)
Спасибо заранее,
С наилучшими пожеланиями.
Ответы
Ответ 1
Привет всем,
Проследив мой путь через исходный код, я, наконец, придумал решение для этого. Если вы используете factory_girl 1.3.2 (который был последним выпуском в то время, когда я пишу это), вы можете добавить следующий код в начало вашего файла factory.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, такие как:
Factory.define :specialty do |f|
f.sequence(:title) { |n| "Test Specialty #{n}"}
f.sequence(:permalink) { |n| "permalink#{n}" }
end
Я еще не написал код для обработки: Factory.sequence...
Надеюсь, это поможет всем остальным разочарованным людям, которые не могут понять, почему в мире factory девушка этого не дает. Возможно, я перекрою проект github и отправлю запрос на перенос с этим исправлением, поскольку он не изменяет никакой внутренней функциональности.
-Эндрю
Ответ 2
Просто вызовите 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 секунд для запуска в любом случае. Поэтому накладных расходов недостаточно, чтобы повлиять на мой рабочий процесс.
Ответ 3
Для людей с поисковой системой: без дальнейшего расширения просто 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)
fooobar.com/questions/222784/...
Ответ 4
В соответствии с WhileBot Здесь, необходимость reset последовательности между тестами - это анти-шаблон.
Легализовать:
Если у вас есть что-то вроде этого:
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"
Ответ 5
Чтобы гарантировать, что последовательности идут от 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, когда они вносят изменения, это может не работать должным образом.
Ответ 6
Нет последовательности в reset последовательности, см. здесь исходный код:
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
В reset определенную последовательность вы можете попробовать
# 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
Если вы используете Cucumber, вы можете добавить это к определению шага:
Given(/^I reload FactoryGirl/) do
FactoryGirl.reload
end
Затем просто вызовите его, когда это необходимо.