2016-04-05 4 views
1

Ich habe Land Fabrik, die für die so etwas wie diesesDer beste Weg, die Eindeutigkeit eines 2-stelligen Feldes innerhalb einer Fabrik zu erzwingen?

FactoryGirl.define do 
    factory :country do 
    name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" } 
    alpha { ('a'..'z').to_a.shuffle.join.first(2) } 
    end 
end 

alpha ist ein 2 Ländercode, sieht ich Einzigartigkeit bestätigen.

validates :alpha, 
    presence: true, 
    uniqueness:true, 
    length: {is: 2} 

Wenn große Tests laufen, laufe ich oft in

ActiveRecord::RecordInvalid: 
     Validation failed: Alpha has already been taken 

Insbesondere bei Aufzeichnungen Kind zu schaffen

factory :state do 
    name { "State_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" } 
    country 
end 

Gibt es einen besseren Weg, um mein Land Fabrik zu bauen um Duplikate zu vermeiden? Oder gibt es einen besseren Weg, um den Zustand Fabrik zu bauen, so dass das belongs_to Land eine Mischung aus neuen und vorhandenen Datensätze

Die Lösung

Für alle anderen hier mit einem ähnlichen Problem kommen, Sequenzen sind definitiv der Weg zu geh (danke born4new und Slicedpan).

Bei der Umsetzung erkannte ich, dass ich einige andere Probleme hatte, die Probleme verursachten.

Zunächst wurde der Datenbank-Cleaner nicht ordnungsgemäß ausgeführt, sodass die Datenbank zwischen den Tests nicht auf einen sauberen Status zurückgesetzt wurde. Daher stieß ich ziemlich schnell auf Duplikate.

Ich fand auch, dass ich FactoryGirl Sequenzen nach jedem Test zurücksetzen musste. Ansonsten sah ich für lange Sequenzen zx, zy, zz, a, b, und die einzelnen Zeichen fehlten meine Validierungen.

#spec/rails_helper.rb 
config.append_after(:each) do 
    DatabaseCleaner.clean 
    FactoryGirl.reload 
end 

Antwort

2

Wenn Dinge einzigartig sein müssen, neige ich dazu, Sequenzen zu verwenden. Für den Ländercode müssen Sie die möglichen Ländercodes auflisten. Eine Möglichkeit ist, unter

sequence :country_code do |n| 
    i1 = n % 26 
    i2 = n/26 
    chars = ('a'..'z').to_a 
    "#{chars[i1]}#{chars[i2]}" 
end 

dann in Ihrem Betrieb können Sie einfach tun

factory :country do 
    name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" } 
    alpha { generate :country_code } 
end 
+0

danke @slicedpan, das ist eine gute Idee. Ich hatte mir Sequenzen angesehen, aber meine Implementierung war nicht so vollständig wie deine. Weißt du wie/wann während eines Tests Factorygirl die Sequenz neu startet? Ist es für die gesamte Dauer der Testsuite oder für eine bestimmte Spezifikation oder ..? Ich schien immer noch in Duplikate zu laufen –

+0

Sollte für die gesamte Suite soweit ich weiß – Slicedpan

2

Wenn große Tests laufen,

Sie höchstens haben (vielleicht ein bisschen weniger sein) 26^2 = 676 mögliche Kombinationen für Alpha, also, wenn large tests bedeutet mehr als das, es gibt keinen Weg um ihn herum.

Für das Argument nehme ich an, es ist weniger als das.

Sie von 'AA' beginnen könnte und 'Erhöhung' es wie so:

AB AC ... AZ BA BB BC ...etc

Um dies zu tun, könnten Sie mit Fabrik Mädchens Sequenzen (mit modulos und divisons) spielen:

sequence(:alpha) do |n| 
    ('a'..'z').to_a[n/26] + ('a'..'z').to_a[n % 26] 
end 
+0

danke @ born4new. Weißt du, wann FactoryGirl die Sequenz neu startet? Wird es für die Dauer der Suite oder für eine bestimmte Spezifikation oder ... fortgesetzt? –

+0

Ich glaube, es ist für die ganze Testsuite. Sie sind eingestellt, sobald Sie FactoryGirl geladen haben (so nehme ich an, in Ihrer 'rails_helper' Datei). – born4new

0

Dies ist weniger effizient als Sequenzen (da es sich um eine Datenbank lesen erfordert), aber Werke gut:

FactoryGirl.define do 
    factory :country do 
    alpha do 
     loop do 
     possible_state = ('a'..'z').to_a.sample(2).join 
     break possible_state unless Country.exists?(alpha: possible_state) 
     end 
    end 
    end 
end 

auch die Verwendung von sample beachten.

Verwandte Themen