2010-07-29 23 views
24

Với điều kiện là tôi có một nhà máy dự ánTôi làm cách nào để đặt lại chuỗi 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 

Và rằng tôi là tạo ra các trường hợp của dự án

Factory.build :project 
Factory.build :project 

Đến thời điểm này, lần sau tôi thực hiện Factory.build (: Dự án) Tôi sẽ nhận được một thể hiện của dự án với một tiêu đề thiết lập để "dự án 3 tiêu đề" và như vậy. Không đáng ngạc nhiên.

Bây giờ, tôi muốn đặt lại bộ đếm của mình trong phạm vi này. Một cái gì đó như:

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

Cách tốt nhất để đạt được điều này là gì?

Tôi hiện đang sử dụng các phiên bản sau:

factory_girl (1.3.1) factory_girl_rails (1.0)

Cảm ơn trước, Trân trọng.

+0

Hi ai có thể cho tôi biết nơi bạn đã thêm tệp factories.rb. Trong các tính năng tập tin hoặc trong tập tin spec. – Selvamani

Trả lời

9

Xin chào mọi người, Sau khi truy tìm theo cách của tôi thông qua mã nguồn, tôi cuối cùng đã tìm ra giải pháp cho việc này. Nếu bạn đang sử dụng factory_girl 1.3.2 (mà là phiên bản mới nhất tại thời điểm tôi đang viết những dòng này), bạn có thể thêm đoạn mã sau vào phía trên cùng của tập tin factories.rb của bạn:

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 

Sau đó, trong env.rb dưa chuột của, chỉ cần thêm:

After do 
    Factory.reset_sequences 
end 

tôi giả sử nếu bạn chạy vào cùng một vấn đề trong các thử nghiệm rspec của bạn, bạn có thể sử dụng rspecs sau: từng phương pháp.

Hiện nay, phương pháp này chỉ mất vào chuỗi xem xét định nghĩa bên trong một nhà máy, chẳng hạn như:

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

tôi chưa viết đoạn code để xử lý: Factory.sequence ...

Hy vọng điều này sẽ giúp tất cả những người thất vọng khác ra khỏi đó, những người không thể hiểu tại sao cô gái nhà máy thế giới lại không cung cấp điều này. Có lẽ tôi sẽ ngã ba dự án github và gửi một yêu cầu kéo với sửa chữa này vì nó không thay đổi bất kỳ chức năng nội bộ của họ.

-Andrew

+0

Hi bất kỳ ai có thể cho tôi biết nơi tôi có thể thêm tập tin factories.rb. Trong các tính năng tập tin hoặc trong tập tin spec. – Selvamani

1

không có xây dựng theo cách để thiết lập lại một chuỗi, xem mã nguồn ở đây:.

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

Tuy nhiên, một số người đã bị hack/khỉ vá tính năng này trong Dưới đây là một ví dụ:

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

+0

Xin chào, tôi cũng đã ẩn nguồn của họ và cũng thấy rằng bài đăng bạn đã liên kết. Chưa biết chính xác cách giải quyết vấn đề của tôi. Factory.sequences hoạt động [rõ ràng] theo cách kỳ lạ. Factory.build (: project) # => project 1 Factory.build (: project) # => project 2 Factory.sequences.delete (: project) Factory.build (: project) # => project 3 Vẫn đang cố gắng tìm ra lý do. – DBA

+0

Trình tự cung cấp cho bạn một ID duy nhất có guarenteed tại đây, chứ không phải số lượng đối tượng. Hành vi đó là chính xác những gì bạn nên mong đợi. Chúng được sử dụng để đảm bảo tên được tạo duy nhất mỗi lần bạn tạo một cá thể từ nhà máy. – Winfield

+1

Đó là chính xác những gì tôi đang cố gắng để thiết lập lại :) – DBA

6

Theo ThoughBot Here, sự cần thiết phải thiết lập lại trình tự giữa các xét nghiệm là một mô hình chống.

Để summerize:

Nếu bạn có một cái gì đó như thế này:

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

kiểm tra của bạn sẽ trông như thế này:

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" 
+2

Tôi thấy nó rất hữu ích để thiết lập lại trình tự giữa các bài kiểm tra, do đó tôi bây giờ chính xác những gì mong đợi trên mỗi và các bài kiểm tra của tôi là khai báo nhiều hơn. – Macario

38

Chỉ cần gọi FactoryGirl.reload vào trước/sau khi gọi lại. Điều này được xác định trong codebase FactoryGirl là:

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

Gọi FactoryGirl.sequences.clear không đủ vì một lý do nào đó. Việc tải lại đầy đủ có thể có một số chi phí, nhưng khi tôi thử với/không có cuộc gọi lại, các thử nghiệm của tôi mất khoảng 30 giây để chạy theo một trong hai cách. Do đó, chi phí không đủ để tác động đến luồng công việc của tôi.

+0

Cảm ơn nó hoạt động. Tôi đã thêm mã này vào tập tin spec-> support-> reset.rb và tôi thêm 'Sau khi làm FactoryGirl.reload end' trong tập tin env.rb – Selvamani

9

Đối googling người: không mở rộng hơn nữa, chỉ cần làm 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" 

công trình đối với tôi trên

* factory_girl (4.3.0) 
* factory_girl_rails (4.3.0) 

https://stackoverflow.com/a/16048658

0

Để thiết lập lại trình tự đặc biệt mà bạn có thể thử

# 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 
+1

Trong phiên bản 4.5.0, tôi đã quản lý nó bằng cách sử dụng' FactoryGirl .configuration.sequences [: iterator] .instance_variable_get ("@ value"). instance_variable_set ("@ value", 1) '(trong đó ': iterator' là tên của chuỗi). Lưu ý rằng điều này chỉ hoạt động trên các chuỗi toàn cầu. –

2

Phải đảm bảo trình tự sẽ từ 1 đến 8 và khởi động lại thành 1 và cứ tiếp tục như vậy. Thực hiện như thế này:

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 

Các doc nói "Giá trị chỉ cần hỗ trợ các phương pháp #next." Nhưng để giữ cho bạn đối tượng CustomSequence đi qua nó cũng cần hỗ trợ phương thức #peek. Cuối cùng tôi không biết nó sẽ hoạt động như thế nào bởi vì nó có thể xâm nhập vào bên trong FactoryGirl, khi chúng thực hiện thay đổi có thể không hoạt động đúng cách

0

Nếu bạn đang sử dụng dưa chuột, bạn có thể thêm nó vào định nghĩa bước:

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

Sau đó, chỉ cần gọi khi cần.

Các vấn đề liên quan