RR

RR (Double Ruby) is a double framework that features a rich selection of double techniques and a terse syntax. xunitpatterns.com/Test%20Double.html

Currently RR implements mocks, stubs, and probes. It is a goal of RR to support a wide range of double techniques and patterns.

Mocks

xunitpatterns.com/Mock%20Object.html

view = controller.template
mock(view).render(:partial => "user_info") {"Information"}

# or
mock(view) do
  render(:partial => "user_info") {"Information"}
end

Stubs

xunitpatterns.com/Test%20Stub.html

jane = User.new
stub(User).find('42') {jane}

Mock Probes

Add verifications that a method was called while actually calling it. The following example verifies render partial will be called and renders the partial.

view = controller.template
mock.probe(view).render(:partial => "right_navigation")
mock.probe(view).render(:partial => "user_info") do |html|
  html.should include("John Doe")
  "Different html"
end

Probes support after_call callbacks. This is useful for Stubbing out a class method and getting its return value. You can also change the return value. This technique is also useful for verifying that you are mocking exists and functions proberly, thereby testing you interface. For example, using ActiveRecord:

mock.probe(User).find('5') do |user|
  mock.probe(user).projects do |projects|
    projects[0..3]
  end
  mock(user).valid? {false}
  user
end

Stub Probes

Intercept the return value of a method call. The following example verifies render partial will be called and renders the partial.

view = controller.template
stub.probe(view).render(:partial => "user_info") do |html|
  html.should include("Joe Smith")
  html
end

Instance of Doubles

Put double scenarios on instances of a Class.

mock.instance_of(User).valid? {false}

Block Syntax

script = MyScript.new
mock(script) do |m|
  m.system("cd #{RAILS_ENV}") {true}
  m.system("rake foo:bar") {true}
  m.system("rake baz") {true}
end

Terse Syntax

One of the goals of RR is to make doubles more scannable. This is accomplished by removing words from a double declaration. Here is RR compared to other mock frameworks:

flexmock(User).should_receive(:find).with('42').and_return(jane) # Flexmock
User.should_receive(:find).with('42').and_return(jane) # Rspec
User.expects(:find).with('42').returns {jane} # Mocha
User.should_receive(:find).with('42') {jane} # Rspec using return value blocks
mock(User).find('42') {jane} # RR

Special Thanks To

With any development effort, there are countless people who have contributed to making it possible. We all are standing on the shoulders of giants.

  • Pivotal Labs for sponsoring RR development

  • Parker Thompson for pairing with me

  • Felix Morio for pairing with me

  • David Chelimsky for encouragement to make the RR framework, for developing the Rspec mock framework, and syntax ideas

  • Gerald Meszaros for his excellent book “xUnit Test Patterns”

  • Dan North for syntax ideas

  • Jim Weirich for developing Flexmock, the first Terse ruby mock framework

  • James Mead for developing Mocha

  • Aslak Hellesoy for Developing Rspec

  • Stephen Baker for Developing Rspec

  • Dave Astels for some BDD inspiration