Support *_list for all (including custom) strategies

This commit is contained in:
Josh Clayton and Joel Oliveira 2012-05-04 12:05:31 -04:00 committed by Joshua Clayton
parent 1325da5174
commit 95a4626daa
5 changed files with 127 additions and 47 deletions

View File

@ -3,6 +3,7 @@ require "active_support/notifications"
require 'factory_girl/errors'
require 'factory_girl/factory_runner'
require 'factory_girl/strategy_syntax_method_registrar'
require 'factory_girl/strategy_calculator'
require "factory_girl/strategy/build"
require "factory_girl/strategy/create"
@ -87,16 +88,7 @@ module FactoryGirl
def self.register_strategy(strategy_name, strategy_class)
strategies.register(strategy_name, strategy_class)
FactoryGirl::Syntax::Methods.module_exec do
define_method(strategy_name) do |name, *traits_and_overrides, &block|
instrumentation_payload = { name: name, strategy: strategy_name }
ActiveSupport::Notifications.instrument("factory_girl.run_factory", instrumentation_payload) do
FactoryRunner.new(name, strategy_name, traits_and_overrides).run(&block)
end
end
end
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
end
def self.strategy_by_name(name)

View File

@ -17,7 +17,11 @@ module FactoryGirl
factory = factory.with_traits(@traits)
end
factory.run(runner_strategy, @overrides, &block)
instrumentation_payload = { name: @name, strategy: runner_strategy }
ActiveSupport::Notifications.instrument("factory_girl.run_factory", instrumentation_payload) do
factory.run(runner_strategy, @overrides, &block)
end
end
end
end

View File

@ -0,0 +1,36 @@
module FactoryGirl
class StrategySyntaxMethodRegistrar
def initialize(strategy_name)
@strategy_name = strategy_name
end
def define_strategy_methods
define_singular_strategy_method
define_list_strategy_method
end
private
def define_singular_strategy_method
strategy_name = @strategy_name
define_syntax_method(strategy_name) do |name, *traits_and_overrides, &block|
FactoryRunner.new(name, strategy_name, traits_and_overrides).run(&block)
end
end
def define_list_strategy_method
strategy_name = @strategy_name
define_syntax_method("#{strategy_name}_list") do |name, amount, *traits_and_overrides|
amount.times.map { send(strategy_name, name, *traits_and_overrides) }
end
end
def define_syntax_method(name, &block)
FactoryGirl::Syntax::Methods.module_exec do
define_method(name, &block)
end
end
end
end

View File

@ -1,43 +1,83 @@
module FactoryGirl
module Syntax
## This module is a container for all strategy methods provided by
## FactoryGirl. This includes all the default strategies provided ({Methods#build},
## {Methods#create}, {Methods#build_stubbed}, and {Methods#attributes_for}), as well as
## the complementary *_list methods.
## @example singular factory execution
## # basic use case
## build(:completed_order)
##
## # factory yielding its result to a block
## create(:post) do |post|
## create(:comment, post: post)
## end
##
## # factory with attribute override
## attributes_for(:post, title: "I love Ruby!")
##
## # factory with traits and attribute override
## build_stubbed(:user, :admin, :male, name: "John Doe")
##
## @example multiple factory execution
## # basic use case
## build_list(:completed_order, 2)
## create_list(:completed_order, 2)
##
## # factory with attribute override
## attributes_for_list(:post, 4, title: "I love Ruby!")
##
## # factory with traits and attribute override
## build_stubbed_list(:user, 15, :admin, :male, name: "John Doe")
module Methods
# Builds and returns multiple instances from this factory as an array. Attributes can be
# individually overridden by passing in a Hash of attribute => value pairs.
#
# Arguments:
# * name: +Symbol+ or +String+
# The name of the factory to be used.
# * amount: +Integer+
# number of instances to be built.
# * traits_and_overrides: +Array+
# [+*Array+] Traits to be applied
# [+Hash+] Attributes to overwrite for this instance.
#
# Returns: +Array+
# An array of instances of the class this factory generates, with generated attributes
# assigned.
def build_list(name, amount, *traits_and_overrides)
amount.times.map { build(name, *traits_and_overrides) }
end
# @!parse FactoryGirl.register_default_strategies
# @!method build(name, *traits_and_overrides, &block)
# (see #strategy_method)
# Builds a registered factory by name.
# @return [Object] instantiated object defined by the factory
# Creates and returns multiple instances from this factory as an array. Attributes can be
# individually overridden by passing in a Hash of attribute => value pairs.
#
# Arguments:
# * name: +Symbol+ or +String+
# The name of the factory to be used.
# * amount: +Integer+
# number of instances to be created.
# * traits_and_overrides: +Array+
# [+*Array+] Traits to be applied
# [+Hash+] Attributes to overwrite for this instance.
#
# Returns: +Array+
# An array of instances of the class this factory generates, with generated attributes
# assigned.
def create_list(name, amount, *traits_and_overrides)
amount.times.map { create(name, *traits_and_overrides) }
end
# @!method create(name, *traits_and_overrides, &block)
# (see #strategy_method)
# Creates a registered factory by name.
# @return [Object] instantiated object defined by the factory
# @!method build_stubbed(name, *traits_and_overrides, &block)
# (see #strategy_method)
# Builds a stubbed registered factory by name.
# @return [Object] instantiated object defined by the factory
# @!method attributes_for(name, *traits_and_overrides, &block)
# (see #strategy_method)
# Generates a hash of attributes for a registered factory by name.
# @return [Hash] hash of attributes for the factory
# @!method build_list(name, amount, *traits_and_overrides)
# (see #strategy_method_list)
# @return [Array] array of built objects defined by the factory
# @!method create_list(name, amount, *traits_and_overrides)
# (see #strategy_method_list)
# @return [Array] array of created objects defined by the factory
# @!method build_stubbed_list(name, amount, *traits_and_overrides)
# (see #strategy_method_list)
# @return [Array] array of stubbed objects defined by the factory
# @!method attributes_for_list(name, amount, *traits_and_overrides)
# (see #strategy_method_list)
# @return [Array<Hash>] array of attribute hashes for the factory
# @!method strategy_method
# @!visibility private
# @param [Symbol] name name of the factory to build
# @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
# @param [Proc] block block to be executed
# @!method strategy_method_list
# @!visibility private
# @param [Symbol] name name of the factory to execute
# @param [Integer] amount the number of instances to execute
# @param [Array<Symbol, Symbol, Hash>] traits_and_overrides splat args traits and a hash of overrides
# Generates and returns the next value in a sequence.
#

View File

@ -41,6 +41,14 @@ describe "register custom strategies" do
FactoryGirl.build(:named_object).name.should == "Great"
FactoryGirl.insert(:named_object).name.should == "Custom strategy"
end
it "allows using the *_list method to build a list using a custom strategy" do
FactoryGirl.register_strategy(:insert, custom_strategy)
inserted_items = FactoryGirl.insert_list(:named_object, 2)
inserted_items.length.should == 2
inserted_items.map(&:name).should == ["Custom strategy", "Custom strategy"]
end
end
describe "including FactoryGirl::Syntax::Methods when custom strategies have been declared" do