How can I reset a factory_girl sequence?

后端 未结 9 1927
梦毁少年i
梦毁少年i 2020-12-16 10:17

Provided that I have a project factory

Factory.define :project do |p|
  p.sequence(:title)    { |n| \"project #{n} title\"                  }
  p.sequence(:         


        
相关标签:
9条回答
  • 2020-12-16 10:54

    According to ThoughBot Here, the need to reset the sequence between tests is an anti-pattern.

    To summerize:

    If you have something like this:

    FactoryGirl.define do
      factory :category do
        sequence(:name) {|n| "Category #{n}" }
      end
    end
    

    Your tests should look like this:

    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"
    

    Not This:

    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"
    
    0 讨论(0)
  • 2020-12-16 10:56

    This is pretty old, but it's the top result on google for the relevant keywords. For anyone else stumbling across this.

    There is a class method called sequence_by_name to fetch a sequence by name, and then you can call rewind and it'll reset to 1.

    FactoryBot.sequence_by_name(:order).rewind
    

    Or if you want to reset all.

    FactoryBot.rewind_sequences
    

    Here is the link to the file on github

    0 讨论(0)
  • 2020-12-16 10:58

    There's no built in way to reset a sequence, see the source code here:

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

    However, some people have hacked/monkey-patched this feature in. Here's an example:

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

    0 讨论(0)
  • 2020-12-16 11:01

    Hey everybody, After tracing my way through the source code, I have finally come up with a solution for this. If you're using factory_girl 1.3.2 (which was the latest release at the time I am writing this), you can add the following code to the top of your factories.rb file:

    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
    

    Then, in Cucumber's env.rb, simply add:

    After do
      Factory.reset_sequences
    end
    

    I'd assume if you run into the same problem in your rspec tests, you could use rspecs after :each method.

    At the moment, this approach only takes into consideration sequences defined within a factory, such as:

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

    I have not yet written the code to handle: Factory.sequence ...

    Hope this helps all the other frustrated people out there who cannot understand why in the world factory girl doesn't provide this already. Maybe I'll fork the github project and submit a pull request with this fix since it doesn't change any of their internal functionality.

    -Andrew

    0 讨论(0)
  • 2020-12-16 11:04

    If you are using Cucumber you can add this to a step definition:

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

    Then just call it when needed.

    0 讨论(0)
  • 2020-12-16 11:07

    For googling people: without further extending, just do 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"
    

    works for me on

    * factory_girl (4.3.0)
    * factory_girl_rails (4.3.0)
    

    https://stackoverflow.com/a/16048658

    0 讨论(0)
提交回复
热议问题