Как я могу сбросить последовательность factory_girl? - PullRequest
27 голосов
/ 29 июля 2010

При условии, что у меня есть фабрика проекта

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 с заголовком, установленным в «заголовок проекта 3» и так далее.Не удивительно.

Теперь скажите, что я хочу сбросить счетчик в этой области.Что-то вроде:

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)

Заранее спасибо, С наилучшими пожеланиями.

Ответы [ 9 ]

43 голосов
/ 09 декабря 2011

Просто вызовите FactoryGirl.reload в вашем обратном вызове до / после. Это определяется в кодовой базе FactoryGirl как:

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

Вызов FactoryGirl.septions.clear по некоторым причинам недостаточен. Выполнение полной перезагрузки может потребовать некоторых дополнительных затрат, но когда я попытался с / без обратного вызова, мои тесты заняли около 30 секунд для запуска в любом случае. Поэтому накладных расходов недостаточно, чтобы повлиять на мой рабочий процесс.

11 голосов
/ 07 января 2011

Привет всем, Проследив мой путь через исходный код, я наконец-то нашел решение для этого. Если вы используете 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

Затем в env.rb от Cucumber просто добавьте:

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 и отправлю запрос на извлечение с этим исправлением, поскольку оно не меняет их внутреннюю функциональность.

-Эндрю

9 голосов
/ 03 февраля 2014

Для людей, прибегающих к помощи: без дальнейшего расширения, просто сделайте 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

6 голосов
/ 02 ноября 2011

По словам ХотяБота Здесь , необходимость сброса последовательности между тестами - это анти-паттерн.

Подвести итог :

Если у вас есть что-то вроде этого:

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"
3 голосов
/ 04 января 2019

Это довольно старый, но это лучший результат в Google по релевантным ключевым словам.Для всех, кто споткнулся через это.

Существует метод класса с именем sequence_by_name для извлечения последовательности по имени, а затем вы можете вызвать rewind, и он сбросится до 1.

FactoryBot.sequence_by_name(:order).rewind

Или еслихочу сбросить все.

FactoryBot.rewind_sequences

Вот ссылка на файл на github

2 голосов
/ 03 ноября 2014

Нужно было убедиться, что последовательности идут от 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, когда они вносят изменения, это может не работать должным образом

1 голос
/ 29 июля 2010

Нет встроенного способа сброса последовательности, см. Исходный код здесь:

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

Однако некоторые люди взломали / залатали эту функцию. Вот пример:

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

0 голосов
/ 26 сентября 2017

Если вы используете огурец, вы можете добавить это к определению шага:

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

Тогда просто позвоните, когда нужно.

0 голосов
/ 02 июля 2014

Для сброса определенной последовательности вы можете попробовать

# 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
...