<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <title>A quick guide to Mocha</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>

<h1>A quick guide to Mocha</h1>
<h2>Overview</h2>
<p>
Mocha is a framework for creating mock objects and stubbing methods of
existing classes.
</p>
<ul>
<li>Mocha lets users create mock objects and test expectations on those objects

</li>
<li>Mocha lets users stub methods on exiting objects (For a single object, for
any object of a given class, or for singleton objects)

</li>
<li>Mocha is integrated with Ruby&#8217;s <a
href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a>
such that failed expectations with fail <a
href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a>
tests, and stubs will be removed at the end of each test.

</li>
</ul>
<h2>Unit testing, mock objects and stubs</h2>
<p>
<a href="http://en.wikipedia.org/wiki/Unit_test">Unit testing</a> is a
technique by which you write tests for your code to make sure it works as
expected, and future additions do not break existing code. It is called
&quot;unit&quot; testing because you only test a single unit of your own
code (for instance just one class), and you only test your own code. The
problem is that code often has many dependencies, and it is difficult to
test it in isolation.
</p>
<p>
There are two ways of dealing with this problem :
</p>
<ul>
<li><b>Mock objects</b> : substitute real objects with mock objects, and verify
that the object is being used as expected.

</li>
<li><b>Stubs</b> : Replace specific methods of existing objects (including
singleton objects) to return canned (pre-defined) data.

</li>
</ul>
<h2>Example with Mocha</h2>
<h3>Mock objects</h3>
<p>
Say we are writting a class for logging error messages to a file, and we
want to test it. The class responds to two methods :
&#8216;output_to&#8217; which sets the IO object on which to ouput, and
&#8216;log&#8217; which takes a message to output :
</p>
<pre>
  class MyLogger
    def output_to(file)
      @file = file
    end
    def log(msg)
      @file &lt;&lt; msg
    end
  end
</pre>
<p>
The problem is the &#8216;file&#8217; object - we don&#8217;t want to use a
real file, because it might make the test fail even though our code is
correct (for instance if we don&#8217;t have write access to the current
directory). So we create a mock object to replace the file :
</p>
<pre>
  mockfile = mock('file')
</pre>
<p>
At this point, we want to make sure that &#8217;&lt;&lt;&#8217; is called
on our file object (This is called, rightly, an expectation). This is done
this way :
</p>
<pre>
  mockfile.expects(:&lt;&lt;)
</pre>
<p>
Here the call to &#8216;expects&#8217; on the mock object does two things :
</p>
<ol>
<li>It ensures that the test will succeed only if &#8217;&lt;&lt;&#8217; is
called on mockfile

</li>
<li>It returns a Mocha::Expectation object

</li>
</ol>
<p>
The Mocha::Expectation objects can be used to further narrow what is
expected when &#8217;&lt;&lt;&#8217; is called. For instance if we want to
make sure that the call to &#8217;&lt;&lt;&#8217; gets the string
&#8216;some message&#8217; we can write :
</p>
<pre>
  mockfile.expects(:&lt;&lt;).with('some message')
</pre>
<p>
Calls to Mocha::Expectation object are chainable, so the expectation can be
narrowed further in the same line. For instance, we could add that
&#8217;&lt;&lt;&#8217; must be called twice with &#8216;some message&#8217;
:
</p>
<pre>
  mockfile.expects(:&lt;&lt;).times(2).with('some message')
</pre>
<p>
Mocha::Expectation also allows to define the behaviour of the mocked method
- what it returns, yields or raises. For instance in this case,
&#8217;&lt;&lt;&#8217; should really return mockfile - or we might get into
trouble since calls to &#8217;&lt;&lt;&#8217; can be chained :
</p>
<pre>
  mockfile.expects(:&lt;&lt;).times(2).with('some message').returns(mockfile)
</pre>
<p>
We are now ready to write our test :
</p>
<pre>
  def test_output_to_file
    mockfile = mock('file')
    mockfile.expects(:&lt;&lt;).times(2).with('some message').returns(mockfile)

    MyLogger.output_to(mockfile)
    MyLogger.log('some message')
    MyLogger.log('some message')
  end
</pre>
<h3>Stubs</h3>
<p>
Next we want to be able to pass a file name directly to
&#8216;output_to&#8217;, so we don&#8217;t have to bother opening the file
ourselves. Our new MyLogger class looks like this :
</p>
<pre>
  class MyLogger
    def output_to(file)
      if file.kind_of? String
        @file = File.open(file, 'a+')
      else
        @file = file
      end
    end
    def log(msg)
      @file &lt;&lt; msg
    end
  end
</pre>
<p>
And we want to test this new behaviour. Now we encounter a new problem : we
can&#8217;t use a mock object to replace File, since we don&#8217;t have
the opportunity to pass that object to MyLogger - it uses it directly. So
what we will do is replace (or &quot;stub&quot;) the call to
&#8216;File.open&#8217; with our own code. To make this as straightforward
as possible, Mocha adds methods to the &#8216;Object&#8217; class, so we
can write directly :
</p>
<pre>
  File.expects(:open).with('test.txt', 'a+').returns(mockfile)
</pre>
<p>
Again, we did two different things :
</p>
<ol>
<li>We told File that it had to expect a call to &#8216;open&#8217; with
parameters &#8216;test.txt&#8217; and &#8216;a+&#8217; (the test will fail
otherwise)

</li>
<li>We replaced &#8216;File.open&#8217; shuch that it returns our mock object
instead of a real IO object.

</li>
</ol>
<p>
Our second test looks like this :
</p>
<pre>
  def test_output_to_named_file
    # Create our mock IO object
    mockfile = mock('file')
    mockfile.expects(:&lt;&lt;).with('some message').returns(mockfile)

    # Stub File.open so that it returns our mock object
    File.expects(:open).with('test.txt', 'a+').returns(mockfile)

    # Run our code
    MyLogger.output_to('test.txt')
    MyLogger.log('some message')
  end
</pre>
<h2>The Mocha library</h2>
<p>
The library for mock objects is &#8216;mocha.rb&#8217; and the library for
stubs is &#8216;stubba.rb&#8217;. These should be loaded after Test::Unit :
</p>
<pre>
  require 'test/unit'
  require 'mocha'
  require 'stubba'
</pre>
<p>
Mocha provides three methods for creating mock objects, defined in the
module Mocha::AutoVerify :
</p>
<ul>
<li><b>mock</b> : creates a mock object for which expectations must be
fullfilled

</li>
<li><b>stub</b> : creates a mock object for which expectations do not need to
be fullfilled

</li>
<li><b>stub_everything</b> : creates a mock object that accepts calls to any
method

</li>
</ul>
<p>
The objects created by those three methods respond to the three methods
defined in Mocha::MockMethods :
</p>
<ul>
<li><b>expects</b> : Adds an expectation that a given method must be called.
This returns a Mocha::Expectation object

</li>
<li><b>stubs</b> : Adds an expectation that a given method may be called. This
returns a Mocha::Expectation object

</li>
<li><b>verify</b> : Asserts that all expectations have been fulfilled. This is
called automatically if the mock object was created by one of the methods
in Mocha::AutoVerify

</li>
</ul>
<p>
See the API documentation of Mocha::Expectation for all the possible
expectations
</p>
<h2>Mocha tips</h2>
<h3>Code blocks for &#8216;with&#8217; and &#8216;returns&#8217;</h3>
<p>
The &#8216;with&#8217; and &#8216;returns&#8217; methods accept code
blocks, which can be used for expecting or returning different results when
the same method is called several times. For instance the first test in
<b>Example with Mocha</b> could test for different strings :
</p>
<pre>
  def test_output_to_file
    mockfile = mock('file')
    params = [&quot;some message&quot;, &quot;another message&quot;]
    mockfile.expects(:&lt;&lt;).times(2).with { |p| p == params.shift}.returns(mockfile)

    MyLogger.output_to(mockfile)
    MyLogger.log('some message')
    MyLogger.log('another message')
  end
</pre>
<h3>Shorthand mocks</h3>
<p>
Many mock objects really just return the same value for the same method.
The methods for creating mock objects in Mocha::AutoVerify provide a
shortand notation for these :
</p>
<pre>
  access = mock({:username =&gt; 'joe', :password =&gt; 'ragrag'})
  access.username # Returns 'joe'
  access.passowrd # Returns 'ragrag'
</pre>