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 Proxies/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.proxy(view).render(:partial => "right_navigation")
mock.proxy(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.proxy(User).find('5') do |user|
mock.proxy(user).projects do |projects|
projects[0..3]
end
mock(user).valid? {false}
user
end
Stub Proxy/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.proxy(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