Mocha and ActiveRecord

Everyone:

I've been using Mocha, which I rather love, to help me test-drive some Rails code. I've run up against something a little clunky, and I'm hoping one of you can help me out.

Suppose I have an Order, which has_many OrderItems. Suppose I want to write a test that checks that when I ask the Order to do something, it asks its order items to do that something. I tried to do this like so:

def test_delegates
     order_items = []
     3.times {
         item = mock("order item", :do_something => nil)
         order_items.push(item)
     }

     order = Order.new(:order_items => order_items)
     order.do_something
end

This works with normal objects, but it seems ActiveRecord objects don't like someone passing them Mocha::Mock objects in their constructors. They check that the order items, in this case, are OrderItem objects.

Is there something in ActiveRecord I can override to relax this behavior? I don't like having to create an OrderItem just to add a single stub or expectation.

Thanks for your help.

···

--
J. B. (Joe) Rainsberger :: http://www.jbrains.ca
Your guide to software craftsmanship
JUnit Recipes: Practical Methods for Programmer Testing
2005 Gordon Pask Award for contribution Agile Software Practice

What we tend to do in this case is stub the collection method itself i.e.
Order#order_items.

So you could do something like this...

def test_should_do_something_to_all_order_items
  order_items = Array.new(3) { mock('order item', :do_something => nil) }
  order = Order.new
  order.stubs(:order_items).returns(order_items)

  order.do_something
end

When I have a spare couple of hours I'll be releasing a new version of Mocha
that supports mocking of the is_a?. This will allow you to make this work
with ActiveRecord, but with the disadvantage that you are coupling your test
to the innards of ActiveRecord.

I hope that helps.

···

On 28/11/06, J. B. Rainsberger <jbrains762@gmail.com> wrote:

Suppose I have an Order, which has_many OrderItems. Suppose I want to
write a test that checks that when I ask the Order to do something, it
asks its order items to do that something. I tried to do this like so:

def test_delegates
     order_items =
     3.times {
         item = mock("order item", :do_something => nil)
         order_items.push(item)
     }

     order = Order.new(:order_items => order_items)
     order.do_something
end

This works with normal objects, but it seems ActiveRecord objects don't
like someone passing them Mocha::Mock objects in their constructors.
They check that the order items, in this case, are OrderItem objects.

Is there something in ActiveRecord I can override to relax this
behavior? I don't like having to create an OrderItem just to add a
single stub or expectation.

--
James.

BTW - it's probably better to use the Mocha mailing list -
http://rubyforge.org/mailman/listinfo/mocha-developer

···

--
James.
http://blog.floehopper.org

James Mead wrote:

···

On 28/11/06, J. B. Rainsberger <jbrains762@gmail.com> wrote:

Suppose I have an Order, which has_many OrderItems. Suppose I want to
write a test that checks that when I ask the Order to do something, it
asks its order items to do that something. I tried to do this like so:

def test_delegates
     order_items =
     3.times {
         item = mock("order item", :do_something => nil)
         order_items.push(item)
     }

     order = Order.new(:order_items => order_items)
     order.do_something
end

This works with normal objects, but it seems ActiveRecord objects don't
like someone passing them Mocha::Mock objects in their constructors.
They check that the order items, in this case, are OrderItem objects.

Is there something in ActiveRecord I can override to relax this
behavior? I don't like having to create an OrderItem just to add a
single stub or expectation.

What we tend to do in this case is stub the collection method itself i.e.
Order#order_items.

So you could do something like this...

def test_should_do_something_to_all_order_items
order_items = Array.new(3) { mock('order item', :do_something => nil) }
order = Order.new
order.stubs(:order_items).returns(order_items)

order.do_something
end

When I have a spare couple of hours I'll be releasing a new version of Mocha
that supports mocking of the is_a?. This will allow you to make this work
with ActiveRecord, but with the disadvantage that you are coupling your test
to the innards of ActiveRecord.

I hope that helps.

That's not bad. I think I'd rather stub the collection than sorry about is_a?. I'll give this a shot and let you know how it goes.

Thank you, James.
--
J. B. (Joe) Rainsberger :: http://www.jbrains.ca
Your guide to software craftsmanship
JUnit Recipes: Practical Methods for Programmer Testing
2005 Gordon Pask Award for contribution Agile Software Practice