Mocha is the mocking library used by the Rails team, so it has understandably gained some traction among Rails developers. I have started using it over flexmock lately, but ran into some problems with partial mocks on ActiveRecord objects. The problem stemmed from the fact that ActiveRecord instantiates new records when returning records from finders, which meant that creating partial mocks for a particular record was difficult.
I created a helper method to make this easier, and so far it has cleaned up a bit of my tests.
Using #any_instance is not helpful in the cases I ran into, since I wanted to target a specific record for different expectations.
You could mock out the individual #find or #find_by_* methods as needed in each test, but that didn’t seem ideal to me. Instead, I dug a bit into ActiveRecord to find what method was called when it actually instantiated the records after a find. I discovered that there is an #instantiate method which takes a hash of column=>value pairs from the finder to instantiate those records.
The following is the helper method which I created to do this:
def mock_active_records(*records)
records.each do |record|
record.class.stubs(:instantiate).with(
has_entry('id', record.id.to_s)
).returns(record)
record.stubs(:reload).returns(record)
end
end
Here is an example test:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
setup do
@user = User.create!
@non_pending_order = user.orders.create!
@pending_order = user.orders.create! :pending => true
mock_active_records @non_pending_order, @pending_order
end
test 'cancels pending orders when deactivating user' do
@non_pending_order.expects(:cancel).never
@pending_order.expects(:cancel).once
@user.deactivate!
end
end
This test makes sure that when I deactivate a user, that I call the cancel method on only the pending order.
Now, you may be asking “why don’t I just test the side effects of cancel on the orders?” Well, I feel that what happens during cancel for an order is outside the scope of a unit test for user. In this example, cancel can have a multitude of side effects. In the context of a unit test for a user, I don’t care what happens when I cancel an order. I only care that I do cancel it.
Also, if cancel needed to make an outbound call to another system, I wouldn’t want an external system to be a dependency of my unit test. Mocking out the method removes any external and implementation dependencies in my unit tests (a functional test is a different matter, mind you).
Related Services: Ruby on Rails Development, Custom Software Development


[...] Rails Development: Using Mocha for ActiveRecord Partial Mocks with Finders | Pathfinder Software De… [...]
That works perfectly, thanks! Using it to fake specific records being returned created with FactoryGirl. (Oh, I love WP Hashcash myself.)
Hi,
It is obligatory to save the object before mocking into active record?
Database insertions take much more time than queries.
Probably i misunderstand something?