mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Added support for sequences
This commit is contained in:
parent
6ee6c0282b
commit
fa36b1da4a
7 changed files with 181 additions and 2 deletions
17
README
17
README
|
@ -71,6 +71,23 @@ When using the association method, the same build strategy (build, create, or at
|
|||
post.new_record? # => true
|
||||
post.author.new_record # => true
|
||||
|
||||
== Sequences
|
||||
|
||||
Unique values in a specific format (for example, e-mail addresses) can be
|
||||
generated using sequences. Sequences are defined by calling Factory.sequence,
|
||||
and values in a sequence are generated by calling Factory.next:
|
||||
|
||||
# Defines a new sequence
|
||||
Factory.sequence :email do |n|
|
||||
"person#{n}@example.com"
|
||||
end
|
||||
|
||||
Factory.next :email
|
||||
# => "person1@example.com"
|
||||
|
||||
Factory.next :email
|
||||
# => "person2@example.com"
|
||||
|
||||
== Using factories
|
||||
|
||||
# Build and save a User instance
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'activesupport'
|
||||
require 'factory_girl/factory'
|
||||
require 'factory_girl/attribute_proxy'
|
||||
require 'factory_girl/sequence'
|
||||
|
||||
# Shortcut for Factory.create.
|
||||
#
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
class Factory
|
||||
|
||||
cattr_accessor :factories #:nodoc:
|
||||
cattr_accessor :factories, :sequences #:nodoc:
|
||||
self.factories = {}
|
||||
self.sequences = {}
|
||||
|
||||
attr_reader :name
|
||||
|
||||
|
@ -24,6 +25,41 @@ class Factory
|
|||
self.factories[name] = instance
|
||||
end
|
||||
|
||||
# Defines a new sequence that can be used to generate unique values in a specific format.
|
||||
#
|
||||
# Arguments:
|
||||
# name: (Symbol)
|
||||
# A unique name for this sequence. This name will be referenced when
|
||||
# calling next to generate new values from this sequence.
|
||||
# block: (Proc)
|
||||
# The code to generate each value in the sequence. This block will be
|
||||
# called with a unique number each time a value in the sequence is to be
|
||||
# generated. The block should return the generated value for the
|
||||
# sequence.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }
|
||||
def self.sequence (name, &block)
|
||||
self.sequences[name] = Sequence.new(&block)
|
||||
end
|
||||
|
||||
# Generates and returns the next value in a sequence.
|
||||
#
|
||||
# Arguments:
|
||||
# name: (Symbol)
|
||||
# The name of the sequence that a value should be generated for.
|
||||
#
|
||||
# Returns:
|
||||
# The next value in the sequence. (Object)
|
||||
def self.next (sequence)
|
||||
unless self.sequences.key?(sequence)
|
||||
raise "No such sequence: #{sequence}"
|
||||
end
|
||||
|
||||
self.sequences[sequence].next
|
||||
end
|
||||
|
||||
def build_class #:nodoc:
|
||||
@build_class ||= @options[:class] || name.to_s.classify.constantize
|
||||
end
|
||||
|
|
17
lib/factory_girl/sequence.rb
Normal file
17
lib/factory_girl/sequence.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class Factory
|
||||
|
||||
class Sequence
|
||||
|
||||
def initialize (&proc)
|
||||
@proc = proc
|
||||
@value = 0
|
||||
end
|
||||
|
||||
def next
|
||||
@value += 1
|
||||
@proc.call(@value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -52,6 +52,28 @@ class FactoryTest < Test::Unit::TestCase
|
|||
|
||||
end
|
||||
|
||||
context "defining a sequence" do
|
||||
|
||||
setup do
|
||||
@sequence = mock('sequence')
|
||||
@name = :count
|
||||
Factory::Sequence.stubs(:new).returns(@sequence)
|
||||
end
|
||||
|
||||
should "create a new sequence" do
|
||||
Factory::Sequence.expects(:new).with().returns(@sequence)
|
||||
Factory.sequence(@name)
|
||||
end
|
||||
|
||||
should "use the supplied block as the sequence generator" do
|
||||
Factory::Sequence.stubs(:new).yields(1)
|
||||
yielded = false
|
||||
Factory.sequence(@name) {|n| yielded = true }
|
||||
assert yielded
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "a factory" do
|
||||
|
||||
setup do
|
||||
|
@ -283,4 +305,29 @@ class FactoryTest < Test::Unit::TestCase
|
|||
|
||||
end
|
||||
|
||||
context "after defining a sequence" do
|
||||
|
||||
setup do
|
||||
@sequence = mock('sequence')
|
||||
@name = :test
|
||||
@value = '1 2 5'
|
||||
|
||||
@sequence. stubs(:next).returns(@value)
|
||||
Factory::Sequence.stubs(:new). returns(@sequence)
|
||||
|
||||
Factory.sequence(@name) {}
|
||||
end
|
||||
|
||||
should "call next on the sequence when sent next" do
|
||||
@sequence.expects(:next)
|
||||
|
||||
Factory.next(@name)
|
||||
end
|
||||
|
||||
should "return the value from the sequence" do
|
||||
assert_equal @value, Factory.next(@name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -19,7 +19,11 @@ class IntegrationTest < Test::Unit::TestCase
|
|||
f.first_name 'Ben'
|
||||
f.last_name 'Stein'
|
||||
f.admin true
|
||||
f.email {|a| "#{a.first_name}.#{a.last_name}@example.com".downcase }
|
||||
f.email { Factory.next(:email) }
|
||||
end
|
||||
|
||||
Factory.sequence :email do |n|
|
||||
"somebody#{n}@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -108,4 +112,32 @@ class IntegrationTest < Test::Unit::TestCase
|
|||
|
||||
end
|
||||
|
||||
context "an attribute generated by a sequence" do
|
||||
|
||||
setup do
|
||||
@email = Factory.attributes_for(:admin)[:email]
|
||||
end
|
||||
|
||||
should "match the correct format" do
|
||||
assert_match /^somebody\d+@example\.com$/, @email
|
||||
end
|
||||
|
||||
context "after the attribute has already been generated once" do
|
||||
|
||||
setup do
|
||||
@another_email = Factory.attributes_for(:admin)[:email]
|
||||
end
|
||||
|
||||
should "match the correct format" do
|
||||
assert_match /^somebody\d+@example\.com$/, @email
|
||||
end
|
||||
|
||||
should "not be the same as the first generated value" do
|
||||
assert_not_equal @email, @another_email
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
29
test/sequence_test.rb
Normal file
29
test/sequence_test.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require(File.join(File.dirname(__FILE__), 'test_helper'))
|
||||
|
||||
class SequenceTest < Test::Unit::TestCase
|
||||
|
||||
context "a sequence" do
|
||||
|
||||
setup do
|
||||
@sequence = Factory::Sequence.new {|n| "=#{n}" }
|
||||
end
|
||||
|
||||
should "start with a value of 1" do
|
||||
assert_equal "=1", @sequence.next
|
||||
end
|
||||
|
||||
context "after being called" do
|
||||
|
||||
setup do
|
||||
@sequence.next
|
||||
end
|
||||
|
||||
should "use the next value" do
|
||||
assert_equal "=2", @sequence.next
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue