Ian White

I'm upgrading one of our apps to rails 2.2 and along with that, some plugin dependencies.

In this instance, I needed to monkey patch a method in attachment_fu to make it use the new i18n framework in Rails.

I got to thinking that it would be great if I could be reminded when this monkey patch is no longer necessary (ie. if I upgrade attachmnet_fu, and if it has made that method compatible with i18n). This was easily achieved, using rspec's pending.


pending: it's alive!

(you may want to skip straight to the pending monkey-patch stuff)

You may not know that it you pass a block to pending, it will still run that block, but it will expect it to fail. If the block passes, then rspec will tell you that the example is now working.

Here's an example: Nick is expanding on some specs for some code that I wrote.

it "fred@fang should not be a valid email" do
  @user.email = 'fred@fang'
  @user.should have(1).error_on(:email)
end

The above spec fails because currently, I don't have a complete email regexp. For whatever reason, I tell Nick that I'll look into that at some later point. What do we do next? We could open a ticket, or write a TODO, but what about that spec?

Using pending, we can add some live doco to our app:

it "fred@fang should not be a valid email" do
  pending "a better email regexp" do
    @user.email = 'fred@fang'
    @user.should have(1).error_on(:email)
  end
end

The above code will be shown as PENDING as long as the example fails. When someone gets around to writing a better regexp, the code will pass, and the rspec will fail the build telling you that the example is no longer pending.


Use pending to monitor your monkey-patches

So, we can use this neat feature of rspec to tell us when a monkey-patch is no longer required:

  • Write a spec that exhibits the desired behaviour
  • This spec should fail
  • Wrap the example(s) in pending block(s)
  • (optional, as your app specs might already test this) Write a spec that passes on the monkey-patched code.

In the example given above, all I had to do was spec out the behaviour that attachment_fu should exhibit, then wrap that in an informative pending block.

require File.dirname(__FILE__) + '/../spec_helper'

describe "attachment_fu and i18n" do
  describe "with an invalid attachment" do
    before do
      @model = mock('an attachment_fu model')
      @model.extend Technoweenie::AttachmentFu::InstanceMethods
      @model.stub!(:errors).and_return(mock('errors', :add => nil))
    
      # setup an invalid condition on the model
      @model.stub!(:attachment_options).and_return(:size => (2..3))
      @model.stub!(:size).and_return(1)
    end

    it "#attachment_attributes_valid? should not call default_error_messages" do
      pending "if this passes remove Asset#attachment_attributes_valid?" do
        ActiveRecord::Errors.should_not_receive(:default_error_messages)
        @model.send :attachment_attributes_valid?
      end
    end
  end
end

This means that if I upgrade to a version of attachment_fu that fixes the above problem, my specs will tell me my monkey-patch is no longer required.

1 Response to “Use rspec's pending to monitor your monkey-patches”

  1. Pirsey

    Pirsey Says:

    The style of writing is very familiar to me. Have you written guest posts for other bloggers?

Sorry, comments are closed for this article.