[rspec-users] Mocks? Really?

Andy Goundry andy at adveho.net
Mon Dec 17 06:10:50 EST 2007

For me, this has certainly been the most enjoyable and interesting
part of using RSpec - finding answers to these questions in a context
that suits the project. Of course, i am new to this, but have found an
approach that works well for my current project. However, my approach
is wide open to review and improvement and will no doubt evolve well
beyond its current scope in future.

I am still reading and re-reading Dan's previous mail regarding the
Builder pattern as it is very elegant, although i am not using now as
i feel that it could introduce a little too much overhead to maintain
the Builders. I am also considering Dan's mantra and with more RSpec
experience i'll gain a better insight into how this can work in rails.

Here's what i'm doing that works well for our project:

* In views and controllers I always use mocks and stub out any
responses that i spot or are flagged up by autotest (yep, autotest is
ace for highlighting those methods that need stubbing)
* In models, i only use real models for the model specific to the
test. I always mock all other interacting models - so in a test for a
project with many tasks, the tasks model is mocked and then stubbed.
* I only define the expectation for any mock or real model in one
place. So, in our app, the expected definition of a Project is defined
once and that definition is used by all tests that use that object,
from views to models. It's default values can be overwritten, but the
expectation is set for all uses. More info below:

So far, I am finding that a factory class is offering a useful *glue*
between the intentionally separated unit tests. So, even though all
tests are isolated from each other with mocks, they still share an
expectation of what any used mock should look like. This enables me to
be aware of the system wide impact of a change to a small component of
the system. I fully accept that this should be covered by integration
testing and not unit testing, but on a quick project, i am not sure i
can justify (not yet at least) the time to write unit tests and then
integration tests, especially as the test team will go at the app with
Scellenium. As i say, mine is an evolving platform :-)

Here's how we are using a factory. I hope it helps and that i don't
get too grilled for the design and implementation :-)

# The factory class houses the expected
# definition of each object and returns
# mocks or real models depending on the request
# It's attribute values (but not keys) can be overwritten
# See 'validate_attributes' method below

module Factory
  def self.create_project(attributes = {}, mock = false)
    @default_attributes = {
      :name => "Mock Project",
      :synopsis => "Mock Project Synopsis"


  def self.create_object(custom_attributes,mock,object_type)
    attributes = @default_attributes.merge(custom_attributes)
    if mock
      attributes.each_pair do |key, value|
      mock = object_type.create attributes

  # The following method validates that any received
  # custom attribute's key is in the expected attribute
  # list for the object. If not, the test fails, forcing
  # the developer to keep the factory defaults up to
  # date with any changes
  def self.validate_attributes(attributes)
    attributes.each_key {|a| raise "Unrecognised attribute '#{a}' was
passed into the Factory" if !@default_attributes.has_key?(a)}

# Projects controller test interacts
# with the Factory and receives mocks

describe ProjectsController do
  include Factory
  before(:each) do
    @project1 = Factory.create_project({}, mock_model(Project)),
    @project2 = Factory.create_project({:name => "My second project",
:synopsis => "This is another fantastic project"},
    @projects = [@project1, at project2]

# The Project model test interacts with
# the Factory and receives real models

describe Project do
  include Factory

  before(:each) do
    #Real project
    @project = Factory.create_project
    #Stub Role
    @role = Factory.create_role({},mock_model(Role))

More information about the rspec-users mailing list