03.13.09

How to Setup a Killer Shoulda BDD Rails Testing Environment

Testing in Rails is one of those things that's easy to overlook but hard to live without once you've experienced the benefits of doing so.  I like many Rails started out learning with the book "Agile Web Development with Ruby on Rails."  It was a great book and eventually started me on my path to becoming a full-time freelance web developer, but I have one minor complaint:  the testing section is wayyy at the end of the main tutorial - almost an afterthought. Of course, there wasn't any emphasis on TDD (Test Driven Development) in that book so it makes sense that they would split it out into the post-development section, but the exciting part about Rails, at least to me, was how quickly you could get started on building your own web applications and by the time I had built a few of my own I had all but forgotten about bothering to test at all.

 

It wasn't until I had a few production apps under my belt that I began regretting not giving more attention to testing.  Gradually I grew more and more guilty as I started to attend more Ruby and Rails related conferences and meetups because it became apparent that testing wasn't only a part of Rails but one of the most important parts. Finally, I reached out to the local Ruby users group here in Minnesota asking for some help getting started with testing.  To my relief, I wasn't the only one that wanted to learn more about it, and wouldn't you know it I ended up being the one who gave a talk about getting started with testing in Rails (albeit a fairly rudementary one). 

 

So I will pass what I've learned about testing onto you; "you" being the eager young developer just diving into the world of Ruby on Rails development.  We'll get a nice Behavior Driven Development testing environment setup and go over the basics of what it means to do BDD (or TDD).  Not surprisingly, Mac users will get the most out of this guide since I'm a Mac-head myself, but there will be enough to get started regardless of your platform.

 

 

Setting Up the Testing Environment

 

We will be taking advantage of the following plugins and tools:

There are a few different testing frameworks you can use in Ruby on Rails but I use Shoulda. At the time I was starting to do some research into testing, I queried twitter for advice on which framework to use and shoulda got the most votes, plain and simple.  Rspec is extremely popular too and from what I've learned about it I'm sure I will eventually check it out, but shoulda is nice because it fits neatly into the existing Unit::Test that comes prepackaged with Rails.  Not only that, but there's less "magic" happening so it's a little easier to get up and running with it as a beginner.

 

I'll save the in-depth arguments about why testing is important another blog post, but I should mention a few things about why the test-driven development environment we're about to setup is setup this way and why it's helpful.  The basic idea behind test driven development or behavior driven development (an evolution of TDD) is that you should write tests for your code before you actually write your code.  The advantages are two-fold: writing your tests before your code serves as a roadmap for your development (and documentation as it happen) and it encourages wider test coverage for your code.  It may seem like it's just doubling your workload, but considering most of a developer's time is spent debugging code it's actually going to save you time in the long run.

 

So with this in mind, we've chosen a few tools here that make testing less painful and more integrated into your normal workflow.  The idea here is to write tests and have them run automatically until your code is written and your tests pass.  We start by installing the shoulda gem.

 

Because thoughtbot is recommending that we use their gem instead of the plugin now, we'll add this to our environment.rb file:

 

config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails', :source => "http://gems.github.com"

 

while we're at it we may as well add the other gems we plan to use in our app:

 

config.gem 'webrat', :lib => "webrat", :source => "http://gems.github.com"

config.gem "thoughtbot-factory_girl", :lib => "factory_girl", :source => "http://gems.github.com"

 

Run the rake task in your console to install these gems:


rake gems:install

 

We just need a couple more gems then.  Autotest and Redgreen:

 

sudo gem install ZenTest

sudo gem install redgreen

 

Let's go ahead and install Growl for the Mac while were at it.  Growl, if you don't already know what it is or have it installed, is a nifty little notification system that can be setup to let you know about stuff happening on your computer, from new email messages, download completions, new tweets, and for our purposes, test completions.  This is just a simple mac application installation.

 

We need a special plugin for growl called "growlnotify" which lets us link autotest up with growl.  Assuming the growl installation files are still mounted on your system, in the console navigate to the directory in those setup files containing growlnotify and run this command (should be in /Volumes/Growl/Extras/growlnotify):

 

./install.sh

 

Test to make sure it's installed correctly:


growlnotify -m "Testing" Test

 

If you see a message popup on your screen that says "Testing" you know everything is wired up correctly.

 

Once we have all that stuff installed and ready to rock, we need to do some configuration so that everything is wired up correctly. In your console, create a file in your home directory (~) called .autotest using vim or nano or textmate:

 

vi ~/.autotest

 

and enter the following configuration code into that file and save:

 

Autotest.send(:alias_method, :real_make_test_cmd, :make_test_cmd)
Autotest.send(:define_method, :make_test_cmd) do |*args|
  real_make_test_cmd(*args).sub('test/unit', %[rubygems -e "require 'redgreen'"])
end

module Autotest::Growl
  def self.growl title, msg, img, pri=0, stick=""
    system "growlnotify -n autotest --image #{img} -p #{pri} -m #{msg.inspect} #{title} #{stick}"
  end

  Autotest.add_hook :ran_command do |at|
    output = at.results.last.slice(/(\d+).*errors/)
    if output =~ /ns.*[1-9]/
      growl "Test Results", "#{output}", '~/Library/autotest/rails_fail.png', 2 #, "-s"
    else
      growl "Test Results", "#{output}", '~/Library/autotest/rails_ok.png'
    end
  end
end

 

You'll notice that a couple of images are being referenced here.  They are red/green rails icons that signify a failed or passed test. This helps you when you're making passing glances at your growl test notifications to determine whether or not your tests are passing.  Here's the red and green icons for you to download. You don't have to put them in the same place I did.  Just make sure you reference them correctly in the .autotest file.

 

There's a hack out there that will get autotest to play different sound files based on the outcome of your tests too, but I could never get it working properly so i just turned on the basic sound notification option that comes with Growl which of course doesn't distinguish between passed or failed tests, but at least calls your attention to growl.  Here's a guide on how to get that setup, which is actually quite involved.

 

Whew.  So now that we have our testing environment setup, let's startup our local server for our freshly prepared rails app and see what happens. Open a second tab in your console and run the following command from your rails root directory to get autotest up and running:

 

autotest -rails

 

Assuming you've added a few scaffolds, models, and controllers to your app you will see autotest start to automatically run the canned test that rails automatically generates.  They should all passed provided you haven't added any code of your own yet, and you should see growl notifications popping up with those nifty icons you downloaded earlier.  It is now time to learn a bit about how shoulda and the other tools allow you to do some nifty behavior driven development.

 

In the second part of this post I will discuss Behavior Driven Development with Shoulda, Factory_girl, and Webrat.  Stay tuned.

 

 



Subscribe to Just a Nutter RSS Feed

Scottv on Saturday, March 14, 2009 at 03:16PM

Thanks for posting about this subject Mark. This will help me when I get more into rails.

Jared on Monday, March 16, 2009 at 06:45PM

Just a heads up. If you're running Leopard (Mac OS X 10.5.x), growlnotify has some issues. Essentially, only about a third of the messages sent via growlnotify are actually shown. The others die off somewhere.

I worked through this problem when first upgrading to Leopard. The fix at that time was to use AppleScript. Deets here: http://www.silverchairsolutions.com/blog/?p=19

Mark Nutter on Tuesday, March 17, 2009 at 01:26PM

@Jared I actually didn't run into this issue myself but I saw that other people had, so thanks for the heads up.

Rich Sturim on Friday, March 27, 2009 at 03:22AM

Nice post, thanks for the tips. Just a heads up, there is a great gem on github called growl-glue that make setting up Growl and Autotest very easy. http://is.gd/pb7h

Alderete on Monday, August 31, 2009 at 05:35PM

Your .autotest file is much more complicated than mine. I just have three lines in mine:

require 'redgreen/autotest'
require 'autotest/growl'
require 'autotest/fsevent'

This hooks up RedGreen as I expect, and wires in Growl, too. (The fsevent plugin lets autotest run without constantly polling the filesystem on Mac OS X 10.5+, which gives much better battery life.)

Other than the red/green graphics, what is the rest of your configuration doing beyond the easy-peasy defaults that I'm using? Thanks!

Alderete on Monday, August 31, 2009 at 05:35PM

Your .autotest file is much more complicated than mine. I just have three lines in mine:

require 'redgreen/autotest'
require 'autotest/growl'
require 'autotest/fsevent'

This hooks up RedGreen as I expect, and wires in Growl, too. (The fsevent plugin lets autotest run without constantly polling the filesystem on Mac OS X 10.5+, which gives much better battery life.)

Other than the red/green graphics, what is the rest of your configuration doing beyond the easy-peasy defaults that I'm using? Thanks!

Comment_button_spacer

Current Projects

Area Studios

My web development company and project incubator. We’re always looking for interesting projects. Stop by and check out our work.

View Now

Synopit

A wiki for summaries of the latest long-form news and information articles.

View Now

Twitterless

Receive updates when people stop following you on Twitter and keep track of and learn more about your followers.

View Now

oqodo

Oqodo started as a mini competition between a friend and myself to build an app for our friends to keep in touch. It will soon grow into something much bigger.

View Now

My Web Presence

Flickr
Facebook
Digg
Lastfm
Linkedin
Twitter
Basecamp