Hi there, I''m still trying to wrap my head around when to use a stub and a mock. If I understand this right, I should be using a ''mock'' when imitating an object, but not its behavior. I should be using a stub when I want to imitate the behavior of an object. Does that sound about right? With that said, I''m struggling a little trying to spec out this instance method that is available to a User object. The method takes an OrderPaymentInfo object and copies its attributes onto the User''s attributes (Ignore the clunky design... that''s just how it has to be). The User''s instance method looks like so: class User def update_billing_info(billing_info) unless self.has_billing_address? self.bill_to_address1 = billing_info.address1 self.bill_to_address2 = billing_info.address2 self.bill_to_address3 = billing_info.address3 self.bill_to_city = billing_info.city self.bill_to_country_code = billing_info.country_code self.bill_to_state_province_code = billing_info.state_province_code self.bill_to_postal_code = billing_info.postal_code self.bill_to_phone_number = billing_info.phone_number self.bill_to_extension = billing_info.extension self.bill_to_fax = billing_info.fax_number self.save ? true : false else true end end Here''s the spec: describe User, "when checking billing information" do before(:each) do @user = User.new(:id => 1) @order_payment_info = mock_model(OrderPaymentInfo, :id => 1, :user_id => @user.id, :address1 => "555 Rd.", :address2 => "Ste 2", :address3 => "line 3", :city => "Chicago", :country_code => "USA", :state_province_code => "IL", :psotal_code => "12345", :phone_number => "5551234321", :extension => "123", :fax_number => "5551234321") @user.stub!(:update_billing_info).with(@order_payment_info) end it "should update billing information when User''s billing info is nil" do @user.should_receive(:update_billing_info).with(@order_payment_info) @user.update_billing_info(@order_payment_info) @user.stub!(:has_billing_address?).and_return(false) @user.bill_to_address1.should eql("555 Rd.") @user.bill_to_address2.should eql("Ste 2") end end When I run this spec I get an "error" of: 1) ''User when checking billing information should update billing information when User''s billing info is nil'' FAILED expected "555 Rd.", got nil (using .eql?) I''m just wondering what the best way to approach this would be. Thank you, Dave Hoefler
Op 19-mrt-08, om 16:33 heeft Dave het volgende geschreven:> Hi there, > > I''m still trying to wrap my head around when to use a stub and a mock. > If I understand this right, I should be using a ''mock'' when imitating > an object, but not its behavior. I should be using a stub when I want > to imitate the behavior of an object. Does that sound about right? > > With that said, I''m struggling a little trying to spec out this > instance method that is available to a User object. The method takes > an OrderPaymentInfo object and copies its attributes onto the User''s > attributes (Ignore the clunky design... that''s just how it has to be). > > The User''s instance method looks like so: > > class User > def update_billing_info(billing_info) > unless self.has_billing_address? > self.bill_to_address1 = billing_info.address1 > self.bill_to_address2 = billing_info.address2 > self.bill_to_address3 = billing_info.address3 > self.bill_to_city = billing_info.city > self.bill_to_country_code = billing_info.country_code > self.bill_to_state_province_code = > billing_info.state_province_code > self.bill_to_postal_code = billing_info.postal_code > self.bill_to_phone_number = billing_info.phone_number > self.bill_to_extension = billing_info.extension > self.bill_to_fax = billing_info.fax_number > self.save ? true : false > else > true > end > end >If this is activerecord you could use self.update_attributes(billing_info)> > Here''s the spec: > > describe User, "when checking billing information" do > before(:each) do > @user = User.new(:id => 1) > @order_payment_info = mock_model(OrderPaymentInfo, > :id => 1, > :user_id => @user.id, > :address1 => "555 Rd.", > :address2 => "Ste 2", > :address3 => "line 3", > :city => "Chicago", > :country_code => "USA", > :state_province_code => "IL", > :psotal_code => "12345", > :phone_number => "5551234321", > :extension => "123", > :fax_number => "5551234321") > @user.stub!(:update_billing_info).with(@order_payment_info) > endYou just stubbed update_billing_info (called with @order_payment_info) on @user, which means the real method will not be used anymore. Your tests will use the stub instead of the real method. Don''t stub the very thing you want to test!> > > it "should update billing information when User''s billing info is > nil" do > > @user.should_receive(:update_billing_info).with(@order_payment_info) > @user.update_billing_info(@order_payment_info) > @user.stub!(:has_billing_address?).and_return(false) > @user.bill_to_address1.should eql("555 Rd.") > @user.bill_to_address2.should eql("Ste 2") > end > > > end > > When I run this spec I get an "error" of: > > 1) > ''User when checking billing information should update billing > information when User''s billing info is nil'' FAILED > expected "555 Rd.", got nil (using .eql?) >Try to test one thing at a time, you shouldn''t test everything about that method in one test. To me your test description does not tell a thing: ''User when checking billing information should update billing information when User''s billing info is nil'' This says much more: ''User instance object update_billing_info should update the billing address part 1'' You can build this up like this: describe User, "instance object" do before(:each) do @user = User.create( ... ) end describe "update_billing_info" do it "should update the billing address part 1" do @user.update_billing_info( @order_payment_info ) @user.bill_to_address1.should == "555 Rd." end it "should ..." ... end end Try to make small tests (make a new test if the first works) and try to build the model with the tests instead of the other way around. gr Ivo
Ivo, Thank you for that explanation! That was exactly what I needed. I feel like I understand things more clearly after that. I just need to remember to keep my tests small. Thanks! Dave On Wed, Mar 19, 2008 at 11:01 AM, Ivo Dancet <ivo.dancet at gmail.com> wrote:> Op 19-mrt-08, om 16:33 heeft Dave het volgende geschreven: > > > > > Hi there, > > > > I''m still trying to wrap my head around when to use a stub and a mock. > > If I understand this right, I should be using a ''mock'' when imitating > > an object, but not its behavior. I should be using a stub when I want > > to imitate the behavior of an object. Does that sound about right? > > > > With that said, I''m struggling a little trying to spec out this > > instance method that is available to a User object. The method takes > > an OrderPaymentInfo object and copies its attributes onto the User''s > > attributes (Ignore the clunky design... that''s just how it has to be). > > > > The User''s instance method looks like so: > > > > class User > > def update_billing_info(billing_info) > > unless self.has_billing_address? > > self.bill_to_address1 = billing_info.address1 > > self.bill_to_address2 = billing_info.address2 > > self.bill_to_address3 = billing_info.address3 > > self.bill_to_city = billing_info.city > > self.bill_to_country_code = billing_info.country_code > > self.bill_to_state_province_code > > billing_info.state_province_code > > self.bill_to_postal_code = billing_info.postal_code > > self.bill_to_phone_number = billing_info.phone_number > > self.bill_to_extension = billing_info.extension > > self.bill_to_fax = billing_info.fax_number > > self.save ? true : false > > else > > true > > end > > end > > > > If this is activerecord you could use > self.update_attributes(billing_info) > > > > > > Here''s the spec: > > > > describe User, "when checking billing information" do > > before(:each) do > > @user = User.new(:id => 1) > > @order_payment_info = mock_model(OrderPaymentInfo, > > :id => 1, > > :user_id => @user.id, > > :address1 => "555 Rd.", > > :address2 => "Ste 2", > > :address3 => "line 3", > > :city => "Chicago", > > :country_code => "USA", > > :state_province_code => "IL", > > :psotal_code => "12345", > > :phone_number => "5551234321", > > :extension => "123", > > :fax_number => "5551234321") > > @user.stub!(:update_billing_info).with(@order_payment_info) > > end > > You just stubbed update_billing_info (called with @order_payment_info) > on @user, which means the real method will not be used anymore. Your > tests will use the stub instead of the real method. Don''t stub the > very thing you want to test! > > > > > > > > it "should update billing information when User''s billing info is > > nil" do > > > > @user.should_receive(:update_billing_info).with(@order_payment_info) > > @user.update_billing_info(@order_payment_info) > > @user.stub!(:has_billing_address?).and_return(false) > > @user.bill_to_address1.should eql("555 Rd.") > > @user.bill_to_address2.should eql("Ste 2") > > end > > > > > > end > > > > When I run this spec I get an "error" of: > > > > 1) > > ''User when checking billing information should update billing > > information when User''s billing info is nil'' FAILED > > expected "555 Rd.", got nil (using .eql?) > > > > Try to test one thing at a time, you shouldn''t test everything about > that method in one test. To me your test description does not tell a > thing: > > > ''User when checking billing information should update billing > information when User''s billing info is nil'' > > This says much more: > > ''User instance object update_billing_info should update the billing > address part 1'' > > You can build this up like this: > > describe User, "instance object" do > before(:each) do > @user = User.create( ... ) > end > describe "update_billing_info" do > it "should update the billing address part 1" do > > @user.update_billing_info( @order_payment_info ) > @user.bill_to_address1.should == "555 Rd." > end > it "should ..." ... > end > end > > > Try to make small tests (make a new test if the first works) and try > to build the model with the tests instead of the other way around. > > gr > Ivo > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >