I''m developing a rails application. I have an Order model that has_many OrderItems. I mocked the OrderItem model in my Order specs using mock_model. I thought I should focus my specs on each model and always mock associated models. In my Order model I need a way to merge OrderItems which have the same cost and same product_id. That I can spec. The other thing this merge helper function should do is increment the quantity of the merged OrderItems. Below @order_item1 and @order_item4 would be merged into one item with a quantity of 2. Here are my OrderItems mocks: @order_item1 = mock_model(OrderItem, :valid? => true, :product_id => 1, :cost => 1, :null_object => true) @order_item2 = mock_model(OrderItem, :valid? => true, :product_id => 1, :cost => 2, :null_object => true) @order_item3 = mock_model(OrderItem, :valid? => true, :product_id => 2, :cost => 1, :null_object => true) @order_item4 = mock_model(OrderItem, :valid? => true, :product_id => 1, :cost => 1, :null_object => true) Here is the spec I wrote to check for the quantity: it "should increment the quanity of the merged items" do lambda { @order.valid? }.should change(@order_item1, :quantity).from(1).to(2) end How do I create an attribute for ''quantity'' that has state on my OrderItem mocks? I realize I could do this differently and just do a should_receive on the OrderItem, looking for ''+='' or something, but that doesn''t feel right. I don''t care how it''s incremented, I just want to make sure it''s changed. Thanks, Matt
On Wed, Jun 4, 2008 at 9:06 AM, Matthew Lins <mattlins at gmail.com> wrote:> I realize I could do this differently and just do a should_receive on the > OrderItem, looking for ''+='' or something, but that doesn''t feel right.I know this isn''t what you''re looking for, but note that whether you do: item.quantity = item.quantity + other_item.quantity or item.quantity += other_item.quantity the sequence of calls to item will be the same: first item.quantity, then item.quantity=, with + being sent to the return value of item.quantity in between. To try and help with what you''re actually trying to do, I think you could define a singleton method on your mocked model. class << @order_item1 attr_accessor :quantity end but that''s smelly. It feels to me like the logic for rolling one item into another belongs in OrderItem. So maybe instead your order spec turns out to be something like: @order_item1.should_receive(:merge).with(@order_item4) If the logic for determining whether to merge also moved into OrderItem, Order (and its spec) could forget about all the attributes of OrderItem. -hume.
Thanks John. Yes, I think I''m violating TDA with that merge helper sitting in order. But, it can''t really sit in OrderItem. I think it''ll have to sit on the association proxy. And, I''m assuming that would be tested by an integration test? I think your singleton class on the mock would work too, but you''re right it is messy. I was wondering if there was something built in. Time to redesign!> From: "John D. Hume" <duelin.markers at gmail.com> > Reply-To: rspec-users <rspec-users at rubyforge.org> > Date: Wed, 4 Jun 2008 10:50:45 -0400 > To: rspec-users <rspec-users at rubyforge.org> > Subject: Re: [rspec-users] Mock with an attributes that has state > > On Wed, Jun 4, 2008 at 9:06 AM, Matthew Lins <mattlins at gmail.com> wrote: >> I realize I could do this differently and just do a should_receive on the >> OrderItem, looking for ''+='' or something, but that doesn''t feel right. > > I know this isn''t what you''re looking for, but note that whether you do: > item.quantity = item.quantity + other_item.quantity > or > item.quantity += other_item.quantity > the sequence of calls to item will be the same: first item.quantity, > then item.quantity=, with + being sent to the return value of > item.quantity in between. > > To try and help with what you''re actually trying to do, I think you > could define a singleton method on your mocked model. > class << @order_item1 > attr_accessor :quantity > end > but that''s smelly. > > It feels to me like the logic for rolling one item into another > belongs in OrderItem. So maybe instead your order spec turns out to be > something like: > @order_item1.should_receive(:merge).with(@order_item4) > If the logic for determining whether to merge also moved into > OrderItem, Order (and its spec) could forget about all the attributes > of OrderItem. > > -hume. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users