diff --git a/lib/factory_girl/proxy.rb b/lib/factory_girl/proxy.rb index 2ab3717bb..a9acecd27 100644 --- a/lib/factory_girl/proxy.rb +++ b/lib/factory_girl/proxy.rb @@ -7,7 +7,6 @@ def initialize(klass) end def get(attribute) - nil end def set(attribute, value) @@ -63,7 +62,6 @@ def run_callbacks(name) # FactoryGirl.create(:post) # def association(name, overrides = {}) - nil end def method_missing(method, *args, &block) diff --git a/spec/factory_girl/proxy/attributes_for_spec.rb b/spec/factory_girl/proxy/attributes_for_spec.rb index 23ca0fdff..d2e0148bd 100644 --- a/spec/factory_girl/proxy/attributes_for_spec.rb +++ b/spec/factory_girl/proxy/attributes_for_spec.rb @@ -1,51 +1,42 @@ require 'spec_helper' describe FactoryGirl::Proxy::AttributesFor do - before do - @proxy = FactoryGirl::Proxy::AttributesFor.new(@class) - end + let(:proxy_class) { stub("class") } - describe "when asked to associate with another factory" do - before do - FactoryGirl.stubs(:create) - @proxy.associate(:owner, :user, {}) - end + subject { FactoryGirl::Proxy::AttributesFor.new(proxy_class) } - it "should not set a value for the association" do - (@proxy.result(nil).key?(:owner)).should_not be - end - end + it_should_behave_like "proxy without association support" - it "should return nil when building an association" do - @proxy.association(:user).should be_nil + it "returns a hash when asked for the result" do + subject.result(nil).should be_kind_of(Hash) end - it "should not call Factory.create when building an association" do - FactoryGirl.stubs(:create) - @proxy.association(:user).should be_nil - FactoryGirl.should have_received(:create).never - end + context "after associating a factory" do + let(:attribute) { :owner } - it "should always return nil when building an association" do - @proxy.set(:association, 'x') - @proxy.association(:user).should be_nil - end + before { subject.associate(attribute, :user, {}) } - it "should return a hash when asked for the result" do - @proxy.result(nil).should be_kind_of(Hash) + it "doesn't set that key in the resulting hash" do + subject.result(nil).should_not have_key(attribute) + end + + it "returns nil when asked for that attribute" do + subject.get(attribute).should be_nil + end end describe "after setting an attribute" do - before do - @proxy.set(:attribute, 'value') - end + let(:attribute) { :attribute } + let(:value) { "value" } + + before { subject.set(attribute, value) } - it "should set that value in the resulting hash" do - @proxy.result(nil)[:attribute].should == 'value' + it "sets that value in the resulting hash" do + subject.result(nil)[attribute].should == value end - it "should return that value when asked for that attribute" do - @proxy.get(:attribute).should == 'value' + it "returns that value when asked for that attribute" do + subject.get(attribute).should == value end end end diff --git a/spec/factory_girl/proxy/build_spec.rb b/spec/factory_girl/proxy/build_spec.rb index e8609fe2a..18bcb0fa9 100644 --- a/spec/factory_girl/proxy/build_spec.rb +++ b/spec/factory_girl/proxy/build_spec.rb @@ -1,77 +1,12 @@ require 'spec_helper' describe FactoryGirl::Proxy::Build do - before do - @instance = stub("built-instance", :attribute => "value", :attribute= => nil, :owner= => nil) - @class = stub("class", :new => @instance) - @proxy = FactoryGirl::Proxy::Build.new(@class) - end + let(:instance) { stub("built-instance") } + let(:proxy_class) { stub("class", :new => instance) } - it "should instantiate the class" do - @class.should have_received(:new) - end + subject { FactoryGirl::Proxy::Build.new(proxy_class) } - describe "when asked to associate with another factory" do - before do - @association = "associated-instance" - @associated_factory = stub("associated-factory", :run => @association) - FactoryGirl.stubs(:factory_by_name => @associated_factory) - @overrides = { 'attr' => 'value' } - @proxy.associate(:owner, :user, @overrides) - end - - it "should create the associated instance" do - @associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Create, @overrides) - end - - it "should set the associated instance" do - @instance.should have_received(:owner=).with(@association) - end - end - - it "should run create when building an association" do - association = "associated-instance" - associated_factory = stub("associated-factory", :run => association) - FactoryGirl.stubs(:factory_by_name => associated_factory) - overrides = { 'attr' => 'value' } - @proxy.association(:user, overrides).should == association - associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Create, overrides) - end - - it "should return the built instance when asked for the result" do - @proxy.result(nil).should == @instance - end - - it "should run the :after_build callback when retrieving the result" do - thing_to_call = stub("object", :foo => nil) - @proxy.add_callback(:after_build, proc{ thing_to_call.foo }) - @proxy.result(nil) - thing_to_call.should have_received(:foo) - end - - describe "when setting an attribute" do - before do - @instance.stubs(:attributes=) - @proxy.set(:attribute, 'value') - end - - it "should set that value" do - @instance.should have_received(:attribute=).with('value') - end - end - - describe "when getting an attribute" do - before do - @result = @proxy.get(:attribute) - end - - it "should ask the built class for the value" do - @instance.should have_received(:attribute) - end - - it "should return the value for that attribute" do - @result.should == 'value' - end - end + it_should_behave_like "proxy with association support", FactoryGirl::Proxy::Create + it_should_behave_like "proxy with standard getters and setters", :attribute_name, "attribute value!" + it_should_behave_like "proxy with callbacks", :after_build end - diff --git a/spec/factory_girl/proxy/create_spec.rb b/spec/factory_girl/proxy/create_spec.rb index b1a099fc3..1754ba81f 100644 --- a/spec/factory_girl/proxy/create_spec.rb +++ b/spec/factory_girl/proxy/create_spec.rb @@ -1,95 +1,42 @@ require 'spec_helper' describe FactoryGirl::Proxy::Create do - before do - @instance = stub("built-instance", :attribute => "value", :attribute= => nil, :owner= => nil, :save! => nil) - @class = stub("class", :new => @instance) - @proxy = FactoryGirl::Proxy::Create.new(@class) - end - - it "should instantiate the class" do - @class.should have_received(:new) - end - describe "when asked to associate with another factory" do - before do - @association = "associated-instance" - @associated_factory = stub("associated-factory", :run => @association) - FactoryGirl.stubs(:factory_by_name => @associated_factory) - @overrides = { 'attr' => 'value' } - @proxy.associate(:owner, :user, @overrides) - end + let(:instance) { stub("created-instance", :save! => true) } + let(:proxy_class) { stub("class", :new => instance) } - it "should create the associated instance" do - @associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Create, @overrides) - end + subject { FactoryGirl::Proxy::Create.new(proxy_class) } - it "should set the associated instance" do - @instance.should have_received(:owner=).with(@association) - end - end + it_should_behave_like "proxy with association support", FactoryGirl::Proxy::Create + it_should_behave_like "proxy with standard getters and setters", :attribute_name, "attribute value!" + it_should_behave_like "proxy with callbacks", :after_build + it_should_behave_like "proxy with callbacks", :after_create - it "should run create when building an association" do - association = "associated-instance" - associated_factory = stub("associated-factory", :run => association) - FactoryGirl.stubs(:factory_by_name => associated_factory) - overrides = { 'attr' => 'value' } - @proxy.association(:user, overrides).should == association - associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Create, overrides) - end - - describe "when asked for the result" do - before do - @build_spy = stub("build", :foo => nil) - @create_spy = stub("create", :foo => nil) - @proxy.add_callback(:after_build, proc{ @build_spy.foo }) - @proxy.add_callback(:after_create, proc{ @create_spy.foo }) - @result = @proxy.result(nil) - end - - it "should save the instance" do - @instance.should have_received(:save!) - end - - it "should return the built instance" do - @result.should == @instance - end - - it "should run both the build and the create callbacks" do - @build_spy.should have_received(:foo) - @create_spy.should have_received(:foo) - end + it "saves the instance before returning the result" do + subject.result(nil) + instance.should have_received(:save!) end it "runs a custom create block" do block = stub('custom create block', :call => nil) - @instance.stubs(:save!).raises(RuntimeError) - instance = @proxy.result(block) + subject.result(block) block.should have_received(:call).with(instance) + instance.should have_received(:save!).never end - describe "when setting an attribute" do - before do - @proxy.set(:attribute, 'value') - end + context "callback execution order" do + let(:after_build_callback) { stub("after_build callback", :foo => nil) } + let(:after_create_callback) { stub("after_create callback", :foo => nil) } + let(:callback_sequence) { sequence("after_* callbacks") } - it "should set that value" do - @instance.should have_received(:attribute=).with('value') - end - end + it "runs after_build callbacks before after_create callbacks" do + subject.add_callback(:after_build, proc { after_build_callback.foo }) + subject.add_callback(:after_create, proc { after_create_callback.foo }) - describe "when getting an attribute" do - before do - @result = @proxy.get(:attribute) - end + after_build_callback.expects(:foo).once.in_sequence(callback_sequence) + after_create_callback.expects(:foo).once.in_sequence(callback_sequence) - it "should ask the built class for the value" do - @instance.should have_received(:attribute) - end - - it "should return the value for that attribute" do - @result.should == 'value' + subject.result(nil) end end end - diff --git a/spec/factory_girl/proxy/stub_spec.rb b/spec/factory_girl/proxy/stub_spec.rb index 9e9c52f04..f23d121bf 100644 --- a/spec/factory_girl/proxy/stub_spec.rb +++ b/spec/factory_girl/proxy/stub_spec.rb @@ -1,95 +1,25 @@ require 'spec_helper' describe FactoryGirl::Proxy::Stub do - before do - @instance = stub("instance", :id= => nil, :id => 42) - @class = stub("class", :new => @instance) + let(:instance) { stub("instance", :id= => nil, :id => 42) } + let(:proxy_class) { stub("class", :new => instance) } - @stub = FactoryGirl::Proxy::Stub.new(@class) - end - - it "should not be a new record" do - @stub.result(nil).should_not be_new_record - end - - it "should be persisted" do - @stub.result(nil).should be_persisted - end - - it "should not be able to connect to the database" do - lambda { @stub.result(nil).reload }.should raise_error(RuntimeError) - end - - describe "when a user factory exists" do - before do - @user = "user" - @associated_factory = stub('associate-factory') - FactoryGirl.stubs(:factory_by_name => @associated_factory) - end - - describe "when asked to associate with another factory" do - before do - @instance.stubs(:owner => @user) - @associated_factory.stubs(:run => @user) - @stub.stubs(:set) - @stub.associate(:owner, :user, {}) - end + subject { FactoryGirl::Proxy::Stub.new(proxy_class) } - it "should set a value for the association" do - @stub.result(nil).owner.should == @user - end + it_should_behave_like "proxy with association support", FactoryGirl::Proxy::Stub + it_should_behave_like "proxy with standard getters and setters", :attribute_name, "attribute value!" + it_should_behave_like "proxy with callbacks", :after_stub - it "should set the owner as the user" do - @stub.should have_received(:set).with(:owner, @user) - end + context "asking for a result" do + it { subject.result(nil).should_not be_new_record } + it { subject.result(nil).should be_persisted } - it "should create a stub correctly on the association" do - @associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Stub, {}) + [:save, :destroy, :connection, :reload, :update_attribute].each do |database_method| + it "raises when attempting to connect to the database by calling #{database_method}" do + expect do + subject.result(nil).send(database_method) + end.to raise_error(RuntimeError, "stubbed models are not allowed to access the database") end end - - it "should return the association when building one" do - @associated_factory.stubs(:run => @user) - @stub.association(:user).should == @user - @associated_factory.should have_received(:run).with(FactoryGirl::Proxy::Stub, {}) - end - - describe "when asked for the result" do - it "should return the actual instance" do - @stub.result(nil).should == @instance - end - - it "should run the :after_stub callback" do - @spy = stub("after_stub callback", :foo => nil) - @stub.add_callback(:after_stub, proc{ @spy.foo }) - @stub.result(nil) - @spy.should have_received(:foo) - end - end - end - - describe "with an existing attribute" do - before do - @value = "value" - @instance.stubs(:attribute => @value, :attribute= => @value) - @stub.set(:attribute, @value) - end - - it "should to the resulting object" do - @stub.attribute.should == 'value' - end - - it "should set the attribute as the value" do - @instance.should have_received(:attribute=).with(@value) - end - - it "should retrieve the attribute" do - @stub.attribute - @instance.should have_received(:attribute) - end - - it "should return that value when asked for that attribute" do - @stub.get(:attribute).should == @value - end end end diff --git a/spec/factory_girl/proxy_spec.rb b/spec/factory_girl/proxy_spec.rb index b78e80178..98fd243ef 100644 --- a/spec/factory_girl/proxy_spec.rb +++ b/spec/factory_girl/proxy_spec.rb @@ -3,6 +3,8 @@ describe FactoryGirl::Proxy do subject { FactoryGirl::Proxy.new(Class.new) } + it_should_behave_like "proxy without association support" + it "doesn't raise when assigning a value to an attribute" do expect { subject.set(:name, "a name") }.to_not raise_error end @@ -16,10 +18,6 @@ subject.name.should == "it's a name" end - it "doesn't raise when asked to associate with another factory" do - expect { subject.associate(:owner, :user, {}) }.to_not raise_error - end - it "raises an error when asking for the result" do expect { subject.result(nil) }.to raise_error(NotImplementedError) end diff --git a/spec/support/shared_examples/proxy.rb b/spec/support/shared_examples/proxy.rb new file mode 100644 index 000000000..cb8a2bc87 --- /dev/null +++ b/spec/support/shared_examples/proxy.rb @@ -0,0 +1,91 @@ +shared_examples_for "proxy without association support" do + it "doesn't raise when asked to associate with another factory" do + expect { subject.associate(:owner, :user, {}) }.to_not raise_error + end + + it "does not call FactoryGirl.create when building an association" do + FactoryGirl.stubs(:create) + subject.association(:user) + FactoryGirl.should have_received(:create).never + end + + it "returns nil when building an association" do + subject.set(:association, 'x') + subject.association(:user).should be_nil + end +end + +shared_examples_for "proxy with association support" do |factory_girl_proxy_class| + let(:factory_name) { :user } + let(:association_name) { :owner } + let(:factory) { stub("associate_factory") } + let(:overrides) { { :one => 1, :two => 2 } } + + before do + FactoryGirl.stubs(:factory_by_name => factory) + instance.stubs(association_name => factory_name) + factory.stubs(:run => factory_name) + subject.stubs(:set) + end + + it "sets a value for the association" do + subject.associate(association_name, factory_name, {}) + subject.result(nil).send(association_name).should == factory_name + end + + it "sets the association attribute as the factory" do + subject.associate(association_name, factory_name, {}) + subject.should have_received(:set).with(association_name, factory_name) + end + + it "runs the factory with the correct proxy class" do + subject.associate(association_name, factory_name, {}) + factory.should have_received(:run).with(factory_girl_proxy_class, {}) + end + + it "runs the factory with the correct proxy class and overrides" do + subject.associate(association_name, factory_name, overrides) + factory.should have_received(:run).with(factory_girl_proxy_class, overrides) + end +end + +shared_examples_for "proxy with standard getters and setters" do |attribute, value| + before do + instance.stubs(:"#{attribute}=" => value, :"#{attribute}" => value) + end + + describe "when setting an attribute" do + before do + subject.set(attribute, value) + end + + its(attribute) { should == value } + it { instance.should have_received(:"#{attribute}=").with(value) } + end + + describe "when getting an attribute" do + it { subject.get(attribute).should == value } + + it "retrieves the value from the instance" do + subject.get(attribute) + instance.should have_received(:"#{attribute}") + end + end +end + +shared_examples_for "proxy with callbacks" do |callback_name| + let(:callback) { stub("#{callback_name} callback", :foo => nil) } + + before do + subject.add_callback(callback_name, proc { callback.foo }) + end + + it "runs the #{callback_name} callback" do + subject.result(nil) + callback.should have_received(:foo).once + end + + it "returns the proxy instance" do + subject.result(nil).should == instance + end +end