mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Add AssociationRunner for running associations from strategies
This extracts logic for running factories based on name and either strategy class, symbol representing a strategy, or nil (defaulting to the create strategy)
This commit is contained in:
parent
b79a525c09
commit
7b2fbeac5c
9 changed files with 116 additions and 48 deletions
|
@ -1,6 +1,7 @@
|
|||
require "active_support/core_ext/module/delegation"
|
||||
|
||||
require 'factory_girl/errors'
|
||||
require 'factory_girl/association_runner'
|
||||
require 'factory_girl/strategy'
|
||||
require 'factory_girl/registry'
|
||||
require 'factory_girl/null_factory'
|
||||
|
|
47
lib/factory_girl/association_runner.rb
Normal file
47
lib/factory_girl/association_runner.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
module FactoryGirl
|
||||
class AssociationRunner
|
||||
def initialize(factory_name)
|
||||
@factory_name = factory_name
|
||||
end
|
||||
|
||||
def run(strategy_name_or_object, overrides)
|
||||
strategy = StrategyCalculator.new(strategy_name_or_object).strategy
|
||||
factory.run(strategy, overrides.except(:method))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def factory
|
||||
FactoryGirl.factory_by_name(@factory_name)
|
||||
end
|
||||
|
||||
class StrategyCalculator
|
||||
def initialize(name_or_object)
|
||||
@name_or_object = name_or_object
|
||||
end
|
||||
|
||||
def strategy
|
||||
if strategy_is_object?
|
||||
@name_or_object
|
||||
else
|
||||
strategy_name_to_object
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def strategy_is_object?
|
||||
@name_or_object.is_a?(Class) && @name_or_object.ancestors.include?(::FactoryGirl::Strategy)
|
||||
end
|
||||
|
||||
def strategy_name_to_object
|
||||
case @name_or_object
|
||||
when :build then Strategy::Build
|
||||
when :create then Strategy::Create
|
||||
when nil then Strategy::Create
|
||||
else raise "unrecognized method #{@name_or_object}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,7 +29,10 @@ module FactoryGirl
|
|||
@build_strategy.add_observer(CallbackRunner.new(self.class.callbacks, self))
|
||||
end
|
||||
|
||||
delegate :association, :to => :@build_strategy
|
||||
def association(factory_name, overrides = {})
|
||||
runner = AssociationRunner.new(factory_name)
|
||||
@build_strategy.association(runner, overrides)
|
||||
end
|
||||
|
||||
def instance=(object_instance)
|
||||
@instance = object_instance
|
||||
|
|
|
@ -41,7 +41,7 @@ module FactoryGirl
|
|||
# # author association, and saves the Post.
|
||||
# FactoryGirl.create(:post)
|
||||
#
|
||||
def association(name, overrides = {})
|
||||
def association(runner, overrides)
|
||||
end
|
||||
|
||||
def result(attribute_assigner, to_create)
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
module FactoryGirl
|
||||
class Strategy #:nodoc:
|
||||
class Build < Strategy #:nodoc:
|
||||
def association(factory_name, overrides = {})
|
||||
factory = FactoryGirl.factory_by_name(factory_name)
|
||||
factory.run(get_method(overrides[:method]), overrides.except(:method))
|
||||
def association(runner, overrides)
|
||||
runner.run(overrides[:method], overrides)
|
||||
end
|
||||
|
||||
def result(attribute_assigner, to_create)
|
||||
|
@ -11,17 +10,6 @@ module FactoryGirl
|
|||
run_callbacks(:after_build, result_instance)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_method(method)
|
||||
case method
|
||||
when :build then Strategy::Build
|
||||
when :create then Strategy::Create
|
||||
when nil then Strategy::Create
|
||||
else raise "unrecognized method #{method}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
module FactoryGirl
|
||||
class Strategy #:nodoc:
|
||||
class Create < Strategy #:nodoc:
|
||||
def association(factory_name, overrides = {})
|
||||
factory = FactoryGirl.factory_by_name(factory_name)
|
||||
factory.run(get_method(overrides[:method]), overrides.except(:method))
|
||||
def association(runner, overrides)
|
||||
runner.run(overrides[:method], overrides)
|
||||
end
|
||||
|
||||
def result(attribute_assigner, to_create)
|
||||
|
@ -13,17 +12,6 @@ module FactoryGirl
|
|||
run_callbacks(:after_create, result_instance)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_method(method)
|
||||
case method
|
||||
when :build then Strategy::Build
|
||||
when :create then Strategy::Create
|
||||
when nil then Strategy::Create
|
||||
else raise "unrecognized method #{method}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,8 @@ module FactoryGirl
|
|||
class Stub < Strategy #:nodoc:
|
||||
@@next_id = 1000
|
||||
|
||||
def association(factory_name, overrides = {})
|
||||
factory = FactoryGirl.factory_by_name(factory_name)
|
||||
factory.run(Strategy::Stub, overrides.except(:method))
|
||||
def association(runner, overrides)
|
||||
runner.run(Strategy::Stub, overrides)
|
||||
end
|
||||
|
||||
def result(attribute_assigner, to_create)
|
||||
|
|
31
spec/factory_girl/association_runner_spec.rb
Normal file
31
spec/factory_girl/association_runner_spec.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
require "spec_helper"
|
||||
|
||||
describe FactoryGirl::AssociationRunner do
|
||||
let(:factory) { stub("factory", :run => instance) }
|
||||
let(:instance) { stub("instance") }
|
||||
|
||||
before do
|
||||
FactoryGirl.stubs(:factory_by_name => factory)
|
||||
end
|
||||
|
||||
it "runs a strategy based on a factory name" do
|
||||
FactoryGirl::AssociationRunner.new(:user).run(FactoryGirl::Strategy::Build, {})
|
||||
factory.should have_received(:run).with(FactoryGirl::Strategy::Build, {})
|
||||
end
|
||||
|
||||
it "strips only method from overrides" do
|
||||
FactoryGirl::AssociationRunner.new(:user).run(FactoryGirl::Strategy::Build, { :method => :build, :name => "John" })
|
||||
factory.should have_received(:run).with(FactoryGirl::Strategy::Build, { :name => "John" })
|
||||
end
|
||||
|
||||
it "runs a strategy inferred by name based on a factory name" do
|
||||
FactoryGirl::AssociationRunner.new(:user).run(:build, { :method => :build, :name => "John" })
|
||||
factory.should have_received(:run).with(FactoryGirl::Strategy::Build, { :name => "John" })
|
||||
end
|
||||
|
||||
it "raises if the strategy cannot be inferred" do
|
||||
expect do
|
||||
FactoryGirl::AssociationRunner.new(:user).run(:bogus_strategy, { :method => :build, :name => "John" })
|
||||
end.to raise_error("unrecognized method bogus_strategy")
|
||||
end
|
||||
end
|
|
@ -1,21 +1,29 @@
|
|||
shared_examples_for "strategy without association support" do
|
||||
let(:attribute) { FactoryGirl::Attribute::Association.new(:user, :user, {}) }
|
||||
|
||||
def association_named(name, overrides)
|
||||
runner = FactoryGirl::AssociationRunner.new(name)
|
||||
subject.association(runner, overrides)
|
||||
end
|
||||
|
||||
it "returns nil when accessing an association" do
|
||||
subject.association(:user, {}).should be_nil
|
||||
association_named(:user, {}).should be_nil
|
||||
end
|
||||
|
||||
it "does not attempt to look up the factory when accessing the association" do
|
||||
FactoryGirl.stubs(:factory_by_name)
|
||||
subject.association(:awesome)
|
||||
association_named(:awesome, {})
|
||||
FactoryGirl.should have_received(:factory_by_name).never
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "strategy with association support" do |factory_girl_strategy_class|
|
||||
let(:factory) { stub("associate_factory") }
|
||||
let(:overrides) { { :great => "value" } }
|
||||
let(:factory_name) { :author }
|
||||
let(:factory) { stub("associate_factory") }
|
||||
|
||||
def association_named(name, overrides)
|
||||
runner = FactoryGirl::AssociationRunner.new(name)
|
||||
subject.association(runner, overrides)
|
||||
end
|
||||
|
||||
before do
|
||||
FactoryGirl.stubs(:factory_by_name => factory)
|
||||
|
@ -23,20 +31,23 @@ shared_examples_for "strategy with association support" do |factory_girl_strateg
|
|||
end
|
||||
|
||||
it "runs the factory with the correct overrides" do
|
||||
subject.association(factory_name, overrides)
|
||||
factory.should have_received(:run).with(factory_girl_strategy_class, overrides)
|
||||
association_named(:author, :great => "value")
|
||||
factory.should have_received(:run).with(factory_girl_strategy_class, :great => "value")
|
||||
end
|
||||
|
||||
it "finds the factory with the correct factory name" do
|
||||
subject.association(factory_name, overrides)
|
||||
FactoryGirl.should have_received(:factory_by_name).with(factory_name)
|
||||
association_named(:author, :great => "value")
|
||||
FactoryGirl.should have_received(:factory_by_name).with(:author)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "strategy with :method => :build" do |factory_girl_strategy_class|
|
||||
let(:factory) { stub("associate_factory") }
|
||||
let(:overrides) { { :method => :build, :great => "value" } }
|
||||
let(:factory_name) { :author }
|
||||
let(:factory) { stub("associate_factory") }
|
||||
|
||||
def association_named(name, overrides)
|
||||
runner = FactoryGirl::AssociationRunner.new(name)
|
||||
subject.association(runner, overrides)
|
||||
end
|
||||
|
||||
before do
|
||||
FactoryGirl.stubs(:factory_by_name => factory)
|
||||
|
@ -44,13 +55,13 @@ shared_examples_for "strategy with :method => :build" do |factory_girl_strategy_
|
|||
end
|
||||
|
||||
it "runs the factory with the correct overrides" do
|
||||
subject.association(factory_name, overrides)
|
||||
association_named(:author, :method => :build, :great => "value")
|
||||
factory.should have_received(:run).with(factory_girl_strategy_class, { :great => "value" })
|
||||
end
|
||||
|
||||
it "finds the factory with the correct factory name" do
|
||||
subject.association(factory_name, overrides)
|
||||
FactoryGirl.should have_received(:factory_by_name).with(factory_name)
|
||||
association_named(:author, :method => :build, :great => "value")
|
||||
FactoryGirl.should have_received(:factory_by_name).with(:author)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue