Mocking and stubbing in Ruby on Rails

Ruby testing strategies for RSpec, Mocha, and Flex Mock

Understand the basic foundations behind stubbing and mocking techniques and strategies with this hands-on walkthrough using the three most popular mocking frameworks for Ruby.

Share:

Bruce Tate (bruce@rapidred.com), CTO, WellGood LLC

Bruce TateBruce Tate is a father, mountain biker, and kayaker in Austin, Texas. The CTO of WellGood, LLC and the chief architect behind ChangingThePresent.org, he's also the author of nine books, including Beyond Java, From Java to Ruby, and Ruby on Rails: Up and Running. He spent 13 years at IBM and later formed the RapidRed consultancy, where he specialized in lightweight development strategies and architectures based on Ruby, and in the Ruby on Rails framework. He now works with a team of Rails developers to build and maintain the charity portal, ChangingThePresent.org.



07 November 2007

Also available in Russian Japanese

After publishing my last article on RSpec, several readers approached me and asked what mock objects might look like in RSpec. I must confess that I deliberately dodged the subject of mocking frameworks last time.

The RSpec team has had some internal discussion about whether to continue to invest in building and maintaining a mocking framework or to adopt one of the existing frameworks. In this article, I'll walk you through the basics of stubbing and mocking. Then, I'll show you examples of both using three popular Ruby frameworks.

The problem

Nearly all strategies for testing automation depend on some fundamental concepts. Tests need to be:

  • Repeatable. If you are to automate a test, your test cases should return the same results every time so you can verify those results.
  • Fast. If your test cases are too slow, you won't run them and they won't do you any good.
  • Simple. If tests are too hard to write, you won't write them.

Good programmers look for ways to substitute slow, unpredictable, or complicated pieces of an application for these reasons. After accumulating years of experience, the industry has settled on at least two important techniques to replace different pieces of a system, much like a builder might build temporary scaffolding to support a structure during construction.

Mocks aren't stubs

Almost four years ago, Martin Fowler of ThoughtWorks published a famous blog post called Mocks Aren't Stubs (see Resources for a link). Four years later, most developers still get the concepts confused. (On a side note, maybe we've picked some poor names to describe the concepts, but we're stuck with them now.) Let me clarify the concepts with an analogy.

Every Christmas, my wife and I get out the Christmas tree and decorate it. Raising the tree should be a cherished memory, but for me, it is a nightmare. I have to deal with the lights. Every year, a handful of lights shake loose, taking out a whole strand of lights. In practice, the job is simple. I have to find the bad bulb. I just work through the lights on the strand that is out, testing each one. I can test each one in at least two different ways. These techniques are like stubbing and mocking.

Stubbing
I've learned that I should not just take a working bulb and try to replace each bulb in the strand. More than one bulb could be out. Instead, I test each bulb. Both techniques work. The first testing technique is to take a bulb out and place it in a little battery powered light. If the bulb lights up, the bulb works, and I go on to the next one. If the little demon doesn't light up, I pound it to a pulp with my hammer and replace it with one that works. You can see what I'm doing. I am replacing the complicated string of lights with a much more simple machine. I then exercise the bulb by putting electricity through it, observe the results, and pass or fail the test accordingly.

Now, think of that bulb as a class or component. The client code that uses the object is the light strand. The socket is the interface. Stubbing preserves the interface but replaces some or all of the client code for the object under test.

Mocking
Mock objects are similar, but a little more complicated. If I don't have a light bulb tester, I can easily use a tool called a voltmeter. A voltmeter measures whether electricity flows through the bulb. The process is similar. I take out each bulb and test it with a voltmeter, placing two electrodes against the bulb. The voltmeter attempts to put a tiny amount of electricity through the circuit and then measures whether electricity flows. If you stretch your mind a little, you can see that what I'm actually doing is measuring how the bulb uses the circuit with a voltmeter. So a mock object is a kind of stub. It replaces the client code that uses the object under test. But the mock object does more. It measures how the object under test actually uses the client code.

A database stub might respond to a query by returning fake records. A mock would do that too, but a mock database object might also make sure the client code called certain queries and ultimately called close to close a connection. You should use a mock when your test depends on how the interface gets used, and a stub when you don't care at all.

The downside

Stubbing and mocking are powerful techniques that can improve the speed of your test cases, isolate your code, simplify your tests, and—some believe—solve world hunger. You know there's always a big 'but.' With mocking and stubbing, you have to be careful not to replace too much of the real world. I've worked with many a client who has ultimately stubbed out anything resembling the real world. Keep in mind that at some point, you need to test that nasty database code with the rest of the application. Consider yourself warned.


Stubbing basics

When you're building any stub for any framework, your approach is basically the same. You have to do two things:

  1. Replace part of the real-world system within your test case with a stub.
  2. Replicate the real-world behavior that you want within your stub.

You might decide to replace a whole object or simply change the results of a single method. When you're replacing a whole object, it's easy—just write the new object and replace it within your test case. Methods might be tougher in some languages, but using dynamic languages such as Ruby, stubbing is easy because you're simply redefining a method. Whew. This theory is getting a little too abstract. It's time to bring these ideas down to earth.

Imagine you have a user interface that prints a document. You want to test code that handles a print failure. You really don't care if the print method gets called. You just want to verify that if your code does call print, that code will handle a failed print effectively. Think of what a pseudo-code sentence would look like.

On an instance of the document object, stub the print method, returning false.

You can break that sentence down into two parts. The first part identifies what you want to stub. The second part defines what the stub should do. Now, it's time to build that stub using three frameworks.

Mocha/Stubba

Right now, one of the top mocking and stubbing frameworks is Mocha. You can install it easily through gems:

Listing 1. Installing Mocha
batate$ gem install mocha
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed mocha-0.5.5
Installing ri documentation for mocha-0.5.5...
Installing RDoc documentation for mocha-0.5.5...

To demonstrate it, I'm going to need an application. My application in Listing 2 will consist of a model called Document and a view called View. The user interface will delegate printing to the Document.

Listing 2. The application in document.rb
class Document
  def print
    # doesn't matter -- we are stubbing it out
  end
end

class View
  attr :document

  def initialize(document)
    @document = document
  end

  def print()
    if document.print
      puts "Excellent!"
      true
    else
      puts "Bummer."
      false
    end
  end
end

I'm not going to bother to build more than a shell for a Document class since I'm just going to stub it out anyway. In fact, one of the great benefits of stubbing frameworks is they allow you to do test-driven development in smaller increments. In this case, I don't have to have a full Document model to build my user interface.

Listing 3 shows the test case.

Listing 3. Testing with Mocha
require 'test/unit'
require 'rubygems'
require 'mocha'
require 'document'

class ViewTest < Test::Unit::TestCase

  def test_should_return_false_for_failed_print
    document = stub("my document")
    document.stubs(:print).returns(false)

    ui = View.new(document)
    assert_equal false, ui.print
  end

end

You can see how this works. I build a simple, named stub object with the statement stub("my document"). Then, I define the behavior for print within the stub with the line of code document.stubs(:print).returns(false). If you look carefully, this line of code looks remarkably similar to the pseudo-code from earlier:

On an instance of the document object, stub the print method, returning false.

I can simplify the first two lines of the test method into one:

Listing 4. Simplifying the test
    Document.any_instance.stubs(:print).returns(false)

The version in Listing 4 substitutes the stub for print into any instance of the Document class. The nice thing about stubbing within the Ruby frameworks is that the syntax might change slightly, but the underlying concepts and structure are exactly the same.

Stubbing with Flex Mock

Along with Mocha, Flex Mock is a popular mocking framework. Jim Weirich, the popular author of everyday Ruby tools such as rake, wrote Flex Mock to handle basic mocking and stubbing in Ruby tests. In terms of popularity and utility, Mocha and Flex Mock are very similar. Installing Flex Mock is easy with gems (another Jim Weirich project):

Listing 5. Installing Flex Mock
gem install flexmock

You can create a stub with the flexmock method. You will supply a hash where the key is the name of the method you want to stub and the value is the return. You'd create a stub with something like you see in Listing 6:

Listing 6. Stubbing with Flex Mock
require 'rubygems'
require 'test/unit'
require 'flexmock/test_unit'
require 'document'

class ViewTest < Test::Unit::TestCase

  def test_should_return_false_for_failed_print
    document = flexmock(:print => false)

    ui = View.new(document)
    assert_equal false, ui.print
  end

end

The syntax is a little different, but the concepts are exactly the same. You're replacing document with a simplified stub that returns false for print.

RSpec

Keep in mind that you can use both Mocha and Flex Mock with RSpec. That said, the syntax for creating a stub with RSpec is similar to Mocha. Listing 7 shows how.

Listing 7. Stubbing with RSpec
document.stub!(:print).and_return(false)

The syntax is strikingly similar to Mocha's syntax. Your main decision with RSpec is whether to use an API that could become deprecated soon or add another testing framework to RSpec. Right now, one of the nice things about RSpec is that it is a one-stop shop for testing. RSpec handles all of the major concerns. But when you look at the syntax of Mocha and RSpec side by side, you'll agree that you don't lose much by using Mocha within RSpec test cases.


Mocking basics

As you've learned, creating a mock object is much like creating a stub. The difference is that a stub is passive—it merely simulates the real-world solution you invoke for stubbed methods. A mock is active—it actually tests the way that you use the mock object. If you don't use it in a way that matches your expectations, your test will fail. These are the basic steps to using a mock:

  1. Replace part of the real-world system within your test case with a stub.
  2. Replicate the real-world behavior that you want within your stub.
  3. Define your expectations.
  4. After your test, compare what happened against your expectations.

Think back to the voltmeter and the Christmas lights. I took out a bulb, which represents the object under test. I then replaced the strand of lights that represented the real-world application with the voltmeter that represented the object under test. I should define two implicit steps. I used a voltmeter because I expected the needle to register current if the bulb worked. After the test, I looked at the voltmeter. These implicit steps represent Step 3 and Step 4. In practice, the testing framework will usually handle Step 4 after the test case completes. A line of pseudo-code describing a mock object for my document printing application might look like this:

For a document object, I expect a call to the print method, which returns false.

Mocking with Mocha, Flex Mock, and RSpec

Often, when you can express an idea in a single sentence, you have a good shot at implementing that idea in a single line or two of Ruby code. Listing 8 shows the incredibly simple Mocha code to change the stub in Listing 4 into a mock.

Listing 8. Simplifying the test
    Document.any_instance.expects(:print).once.returns(false)

I changed the method stubs to expects to reflect my expectation. I also added the once method to show how many times the client code should invoke print. My test case will succeed if and only if my application under test invokes the print method on any instance of the Document class exactly once.

The Flex Mock code to implement mocking is nearly identical to the Mocha version, though the method names are a little different. Listing 9 shows the difference.

Listing 9. Mocking with Flex Mock
    document = flexmock("my document")
    document.should_receive(:print).times(1).and_return(false)

And Listing 10 shows the same in RSpec:

Listing 10. Mocking with RSpec
document = mock("my document")
document.should_receive(:print).and_return(false)

You can add quite a few qualifiers to these mocking frameworks. You can specify expectations for the calling parameters and the number of invocations. You can stub and mock full objects, a single method on an object, or class methods. I'd suggest that you use Flex Mock or Mocha for mocking, at least until discussions about deprecation settle down a little.


Conclusion

If you've been active in Ruby for the last two years, you've noticed a huge investment in advanced testing ideas. Some testing tools have been around for a long time, but now the masses are starting to take notice. As Ruby enthusiasts develop more test cases, techniques like mocking will become more commonplace.

Stubbing and mocking are invaluable techniques to all sorts of Ruby coders. Test first developers will appreciate the ability to mock interfaces that are not fully developed. Programmers with slow test suites can use stubs and mocks to remove expensive interfaces. All testers must use these techniques to add predictability to tests.

Rather than show you an exhaustive review of the mocking libraries in Ruby, I've shown you the concepts behind mocking. I've also given you a quick review of the three most popular mocking libraries. If these concepts are new to you, you still have much to learn, but you should have a sound foundation for further exploration. As always, the best way to learn more is to get coding!

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=267777
ArticleTitle=Mocking and stubbing in Ruby on Rails
publish-date=11072007