---
title: I Mock Your Fixtures, Too
teaser:
tags: web,rails,testing
author: Eric Torrey
published_on: 2007-04-04
---

Mocking is a beautiful thing.  There are no words to describe the immense
pleasure I get from writing a good mocked test.  When I first started writing
tests, I had been unexposed to the glory of mocking.  The days of relying on
fixtures and writing brittle tests are over.

Stub and Mock are brothers that live together.  Stub knew some things about
Mock, and he had a pretty good understanding of how Mock would act.  It didn't
matter much to Stub what Mock did.  Stub knew that Mock would sometimes want to
cook breakfast for Stub, and Stub knew to give Mock some eggs.  Mock sometimes
didn't have any time to make breakfast for Stub, but it didn't bother Stub too
much.  Mock always expected Stub to make lunch.  If Stub didn't make lunch, Mock
would complain until Stub made him lunch. For dinner, they would both usually
get take out.  One night Mock began to make dinner, and Stub was baffled, he
complained to Mock because he was behaving in a way Stub wasn't used to.  Mock
explained to Stub, that sometimes he will make dinner too, and he needs some
eggs.  Stub brought Mock some eggs, and Mock made dinner.  The next night, they
got take out as usual, but Stub didn't mind too much.

```ruby
def show
  @article = Article.find params[:id]
end

def stub_article
  stub('stub article',
    :id => 1,
    :title => 'title',
    :author => 'author',
    :post => stub_everything('post'))
end

def test_should_show_an_article_on_GET_to_show
  article = stub_article
  Article.expects(:find).with('1').returns article

  get :show, :id => '1'

  assert_equal article, assigns(:article)
  assert_response :success
  assert_template 'show'
end
```

The Stub Article will understand and respond to #id, #title, #author, and #post.
When calling @article.any_other_method in the view, it will complain.  The #post
uses `stub_everything`, which is a lazy way to allow something like this:
@article.post.any_other_method.  An Article shouldn't care about what it's Post
can do, but just know that it can have and call its Post.

The functional text expects that Article will call find with "1", and return the
Stub Article.  If any other calls are made on Article, the test complain.  If
the find call is made with something other than "1", the test will complain.

A great deal of faith must be placed in the `find` method on Article that it
does work as advertised.  I can assume that there are tests written for that
method – therefore I don't need to test it during the functional test.  Instead,
I make sure that the instance variable I need is set to the Article Stub, and
that it isn't calling methods that it can't recognize.

```ruby
class Article
  validates_presence_of :title, :author
  def before_create
    self.post = Post.create! :title => title,
      :user => User.find(:first, :conditions => 'admin = true')
  end
end
```

We need to write a unit test for Article to make sure that a Post is created
when an Article is made.  We could use expectations – but when getting to the
low level of testing a model, I prefer to use a more state-based approach.  This
could require the use of fixtures.  We would need to set up a complex network of
Users, Posts, and Articles.  If you note [an earlier post], I really don't like
fixtures much.  Here is the approach I used:

[an earlier post]: https://thoughtbot.com/blog/i-mock-your-fixtures

```ruby
def test_should_create_a_post_for_the_article_before_create
  article = Article.new(:title => 'title')
  User.stubs(:find).returns User.new

  assert ! article.post
  article.save(false)
  assert article.post

  assert_equal Post.find(:first), article.reload.post
end
```

The test uses my newly found and loved method: #.save(false).  My test is only
testing that a Post is created when creating an Article.  If something changes
(a validated attribute is added or removed) on Post – my test will complain,
because that Post will not be created.    I don't care about the User, if
something changes on a User, my test will not break.  I can make the assumption
that the User has its own tests.  I don't care that my Article is invalid (I
don't set the `author` when creating the article), because I know I have another
test for Article creation.

This is my first attempt at preventing broken test chain reactions.  It annoys
me when I make a small change to one Model in a complex application, because
most of my time is spent fixing tests in related functional and unit tests, and
updating fixtures.  Even though the application works fine, I spend all my time
baby sitting tests.
