Mock with an attributes that has state

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 L. [email protected] 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!