mdub@DogBiscuit.org
... mmm, crunchy!
about - weblog - software - resume - email - pgp

Spying on your code with RR

A while back, Melbourne's own Pete Yandell created Not A Mock, an extension to RSpec that supports test-spies. And a damn fine idea it was, too.

I've recently discovered that my current favourite stub/mock framework, Brian Takita's RR, can do test-spies too!

Huh?

What's this "spy" business about? Well, when mocking, before triggering the behaviour you're testing, you set up expectations that a certain methods of collaborating objects will be invoked, with the specified parameters. Like so:

describe TransferEverything do

  before do
    @account1 = Account.new
    @account2 = Account.new
    @transfer = TransferEverything.new(:from => @account1, :to => @account2)
  end

  describe "#execute" do

    it "moves all funds from one account to the other" do

      all_the_money = 1.42
      stub(@account1).balance { all_the_money }

      mock(@account1).withdraw(all_the_money)   # <= set expectations
      mock(@account2).deposit(all_the_money)

      @transfer.execute                         # <= execute
      
    end                                         # <= verify expectations

  end

end

The expectations are typically verified auto-magically, by the mocking framework, at the end of your test.

The spy alternative

Setting up expectations before a call always feels clumsy. Using a test spy makes tests flow more naturally:

  1. Stub out collaborators, setting up canned responses where required.
  2. Execute the code you're testing.
  3. Verify the results, including both:
    • the outputs (return values, or resulting state)
    • the interactions (ie. the method-invocations you expected your fake collaborators to receive).

Fur egg-sample:

describe TransferEverything do

  # ...

  describe "#execute" do

    it "moves all funds from one account to the other" do

      all_the_money = 1.42
      stub(@account1).balance { all_the_money }
      stub(@account1).withdraw
      stub(@account2).deposit

      @transfer.execute

      @account1.should have_received.withdraw(all_the_money)
      @account2.should have_received.deposit(all_the_money)

    end

  end

end

One thing I find particularly useful about this technique is the ability to execute code in a setup block, then verify the various aspects of it's behaviour in separate test-cases.

describe TransferEverything do

  # ...

  describe "#execute" do

    before do
      @all_the_money = 1.42
      stub(@account1).balance { all_the_money }
      stub(@account1).withdraw
      stub(@account2).deposit
      @transfer.execute
    end

    it "withdraws all funds from source account" do
      @account1.should have_received.withdraw(all_the_money)
    end

    it "deposits funds in receiving account" do
      @account2.should have_received.deposit(all_the_money)
    end

  end

end

This results in smaller, more coherent test-cases.

Using RR test-spies in RSpec

If you're using RSpec, you'll need to use the adapter class that comes with RR, rather than the one that comes with RSpec. That is, in your spec_helper.rb, do this, which provides access to the have_received matcher.

require 'rr'
Spec::Runners.configure do |config|
  config.mock_with RR::Adapters::Rspec
end

Spying on Java

Honourable mention: if you're lucky (*cough*) enough to be coding Java, I HIGHLY recommended Mockito, which also implements test-spies, and is easily the best Java mocking/stubbing library around.

ReadOnlyFormBuilder

For RubyOnRails developers, form_for and fields_for are the accepted way of DRYing up form templates. You know the deal; you code

<% form_for :customer, :url => customers_path() do |customer_form| %>
  <p>
    <label>Name:</label> 
    <%= customer_form.text_field :first_name, :size => 15 %>
    <%= customer_form.text_field :last_name, :size => 20 %>
  </p>
  ... etc ...
<% end %>

and you get

<form action="/customers" method="post">
  <p>
    <label>Name:</label> 
    <input id="customer_first_name" name="customer[first_name]" size="15" type="text" />
    <input id="customer_last_name" name="customer[last_name]" size="20" type="text" value="" />
  </p>
  ... etc ...
</form>

Rails generates sensible field names and ids for you, and slurps existing values out of the model object. So far, so good.

Lately, I've taken to using the same trick when presenting data, not just when editing it. So, whereas before I might have written:

  <p>
    <label>Name:</label> 
    <span id="customer_first_name"><%= h @customer.first_name %></span>
    <span id="customer_last_name"><%= h @customer.last_name %></span>
  </p>
  ... etc ...

I'll now code it up as:

<% fields_for :customer, :builder => ReadOnlyFormBuilder do |customer_form| %>
  <p>
    <label>Name:</label> 
    <%= customer_form.text_field :first_name, :size => 15 %>
    <%= customer_form.text_field :last_name, :size => 20 %>
  </p>
  ... etc ...
<% end %>

and get the same output. (In case you're wondering, the ids are there to help with automated testing).

Note the similarity between the last code snippet and the first one on this page; apart from the first line they're indentical. Usually, I'll put the field-declarations themselves in a partial that's shared between "new", "edit" and "show" actions. That way, your "show" page automatically gets identical layout to the others, just with raw values in place of editable fields.

The ReadOnlyFormBuilder class itself it fairly straightforward - I'm planning to wrap it up into a plugin sometime soon. In the meantime, the implementation of text_field looks something like this:

def text_field(attribute, options={})
  content_tag("span", html_escape(value_of(attribute)), :id => "#{@object_name}_#{attribute}")
end

def value_of(attribute)
  value = model.send(attribute)
end

def model
  @object || @template.instance_variable_get("@#{@object_name}")
end

Rake profiling

Where's the bottleneck in your Rake build? Let's find out. Drop (or include) this in your Rakefile:

module Rake
  class Task
    def execute_with_timestamps(*args)
      start = Time.now
      execute_without_timestamps(*args)
      execution_time_in_seconds = Time.now - start
      printf("** %s took %.1f seconds\n", name, execution_time_in_seconds)
    end
    
    alias :execute_without_timestamps :execute
    alias :execute :execute_with_timestamps 
  end
end

method_missing magic - emulating Groovy's "it" in Ruby

Inspired variously by:

I've cooked up a shortcut for generating simple blocks, meaning that rather than

people.select { |x| x.name.length > 10 }

I can write such things as:

people.select(&its.name.length > 10)

Disclaimer: I think this is more "cool hack" than useful tool; it's probably too much of an alien artifact to be useful in real life. And it's not generally applicable, like "it" in Groovy. And really, it's not that much more verbose to use a block. Aaaaaanyway ...

The trick is that the above is parsed as

people.select(&(its.name.length.>(10)))

The "its" method creates a MessageBuffer object, which records the messages (method invocations) sent it's way:

irb(main):001:0> require 'message_buffer'
=> true
irb(main):002:0> its
=> #<MessageBuffer:0x6b40b44 @messages=[]>
irb(main):003:0> its.name.length < 10
=> #<MessageBuffer:0x6b3e678 @messages=[[:name], [:length], [:<, 10]]>

Now, the "&" operator coerces it's argument to a Proc, and MessageBuffer#to_proc generates a Proc that replays all the recorded messages. Q.E.D.

The full source-code is fairly short, so I'll include it inline:

class MessageBuffer 

  instance_methods.each do |m|
    undef_method m unless m =~ /^(__|respond_to|inspect)/ 
  end
  
  def initialize
    @messages = []
  end

  def method_missing(*message)
    @messages << message        # record the message
    self                        # return self so we can keep recording
  end
  
  def __replay_all_messages__(obj)
    @messages.inject(obj) do |obj, message|
      obj.__send__(*message)
    end 
  end
  
  def to_proc
    proc { |x| __replay_all_messages__(x) }
  end

end

def its
  MessageBuffer.new
end


Update: Florian Gross suggested a better way to replay recorded messages, using inject, and I've updated the code accordingly.

Presentation on Ruby/Rails at EJA

A couple of months ago I gave a presentation on Ruby and Rails to a local Java user-group. My slides are now online:

It contains a few examples showing how expressive Ruby can be, when compared to Java.

Tracing with a dynamic Proxy, in Ruby

Recently, I was writing a (Ruby) script to sync email between two IMAP servers. My unit-tests were all working, but something was going screwy when I plugged in a real server.

I wanted to be able to trace the conversation with the IMAP server (or at least, Ruby's IMAP API), to see what was going on. Initially, I started sprinkling tracing statements throughout my code, until I realised that it was going to be easier to define a simple "tracing proxy", and wrap it around the object I wanted to trace:

imap_handle = TracingProxy.new(imap_handle, $stderr)

# ... do stuff with imap_handle ...

It turned out to be straightforward to implement:

class TracingProxy

  def initialize(obj, dest) 
    @obj = obj
    @dest = dest
  end

  def method_missing(symbol, *args)
    arglist = args.map { |a| a.inspect }.join(', ')
    @dest.puts "#{symbol}(#{arglist})"
    rval = @obj.send(symbol, *args)
    @dest.puts ">> #{rval.inspect}"
    rval
  end
  
end

method_missing is a fallback method invoked when the called method isn't found - it's great for implementing dynamic proxies. There's nothing particularly ground-breaking going on here - this kind of trick is fairly common in Ruby-land.

My point is: implementing a dynamic-proxy for tracing was so easy in Ruby that I actually did it. I could have done something similar in Java, using java.lang.reflect.Proxy, or cglib - but I most likely wouldn't have bothered.

In Ruby, implementing the proxy made my life easier, not harder. Ruby encourages me to produce better designs.

Refactoring "support" for Ruby?

These days, there a number of pretty damn good IDEs for Java, with features like intelligent code-completion (aka "intellisense") and automated refactorings. I was a late-starter with IDEs, myself, but even just over the past year I've become annoyingly dependent on some of those IDE features.

Such features depend quite heavily on gleaning data-type information from the code, which is fine for languages like Java and C#. But in dynamically-typed languages like Ruby, we don't have that type info, so things like method-name completion and automated renaming become impossible. (Or so I thought).

Stealing a trick from SmallTalk

It's been puzzling me that there isn't better refactoring support for Ruby, given that the whole concept of refactoring grew out of the SmallTalk community, in the first place. Or more accurately, I've been confused about how automated refactoring could be possible in a dynamic language like SmallTalk.

Then, recently, I stumbled across a paper describing "A Refactoring Tool for Smalltalk", which contains the following explanation:

The Refactoring Browser uses method wrappers to collect runtime information. These wrappers are activated when the wrapped method is called and when it returns. The wrapper can execute an arbitrary block of Smalltalk code. To perform the rename method refactoring dynamically, the Refactoring Browser renames the initial method and then puts a method wrapper on the original method. As the program runs, the wrapper detects sites that call the original method. Whenever a call to the old method is detected, the method wrapper suspends execution of the program, goes up the call stack to the sender and changes the source code to refer to the new, renamed method. Therefore, as the program is exercised, it converges towards a correctly refactored program.

Ah-ha! Cunning.

The Ruby version

As it turns out, we can do much the same thing in Ruby ... leaving aside the "go up the call stack and change the source code" part.

Here's the supporting code:

def method_renamed(h)
  old_name = h.keys[0].to_sym
  new_name = h.values[0].to_sym
  define_method(old_name) { |*args|
    file, line = caller[1].split(':')
    warning = "##{old_name} renamed to ##{new_name}"
    $stderr.puts "#{file}:#{line}: #{warning}"
    send(new_name, *args)
  }
end

Okay, here's a method I want to rename:

class LinkPanel

  def render
    # ... 
  end

end

When I rename it, I also record the change using method_renamed:

class LinkPanel

  method_renamed :render => :to_html

  def to_html
    # ... 
  end

end

Now, I run my tests, and calls to the renamed method result in warnings:

/home/mikew/eyaw/sidebar.rb:229: #render renamed to #to_html

With a single key-chord in my Ruby IDE, I can jump directly to the source-code in question, and fix up the call. I imagine that an ever-so-slightly-more intelligent IDE could complete the refactoring, applying the rename to the call-site automatically! Later on, when I'm confident that everything has been cleaned up, I'll go back and remove that method_renamed alias.

There's more to refactoring than just renaming stuff, of course. I think the "dynamic analysis" trick would be useful to support other refactorings, too ... though I haven't tried it yet.

Proviso: this approach relies on actually running the code, preferably from tests. As the original paper says:

.. the refactoring is only as good as your test suite. If there are pieces of code that are not executed, they will never be analyzed, and the refactoring will not be completed ...