At the Forge - Testing Rails Applications with Shoulda

New to testing? Just want an easier time with Test::Unit? Shoulda is the answer.

The past few months, I've been looking at a number of tools that make it easier for Ruby on Rails developers to improve the reliability of their software using automated testing. Even if you don't fully subscribe to the notion of test-driven development (TDD) or its cousin, behavior-driven development (BDD), the fact that Rails makes it so easy to test each part of your code makes it less likely that foolish mistakes will creep into your applications.

By default, Rails comes with Test::Unit, a test suite that makes it possible, and even easy, to check your code. Coupled with the test classes that come with actionpage, one of the core Ruby gems that comes with Rails, you can create a comprehensive test suite at the unit (model), functional (controller) and integration (cross-controller) levels. If you have a comprehensive test suite, you easily will detect, and understand the implications of, changes you make to the code that break the test.

That said, Test::Unit sometimes can be a bit verbose and repetitive. If you are writing unit tests, and you want to make sure that a particular attribute has been tested completely, it would be nice to be able to express a number of test cases quickly and tersely. Tests can function, in many ways, as a type of specification (as I will explain when we get to RSpec and Cucumber in coming months), and the easier it is to read these specifications, the less likely odd behavior is to slip through the cracks. It also goes without saying that the easier it is to write tests, and particularly comprehensive tests, the more likely you are to write them.

This is why Shoulda, a set of macros that work with Test::Unit, has become popular among Ruby developers in general and Rails developers in particular. Shoulda, developed by Tammer Saleh, a programmer who works for the Thoughtbot consulting company in Boston, is a set of macros that makes it easier to write tests with Test::Unit, as well as easier to read them. I have begun to use Shoulda with projects that I test with Test::Unit and have found it to be quite enjoyable.

This month, I take a look at Shoulda, and how you can integrate its macros into the tests you write in a Rails application. I explain how Shoulda divides tests into contexts, allowing you to group tests together even within a single file. I also describe how Shoulda's various macros make it easy to run a number of tests using a single readable line.

I should note that although Shoulda originally was designed to be used with Test::Unit and to provide something of an RSpec-like environment for Test::Unit users, it adds a growing amount of support for RSpec as well. Even if you use RSpec, you might want to consider using Shoulda along with your standard RSpec tests (or specs). I haven't looked at the combination for my own work, but it might be appropriate for what you're doing.

Installation and Basic Use

Shoulda comes packaged as a Ruby gem, and can be installed as:

sudo gem install thoughtbot-shoulda --source=http://gems.github.com

Earlier versions of Shoulda came packaged under a slightly different name (Shoulda, rather than thoughtbot-shoulda). It also is possible to install Shoulda as a Rails plugin; in this article, I assume that you have installed the gem version.

You can incorporate the gem in your configuration file, config/environment.rb:

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

With that in place, your Rails application either will run with Shoulda in place, or it will fail to load, complaining that the gem has not been installed. In one of my favorite Rails functions, you then can type:

rake gems:install

and your Rails application will examine its list of required gems, download those that are not yet on the system and install them in the appropriate places.

Let's assume you have created a simple Rails application that contains a single model that describes people. You can create it in the following way:

rails simple
cd simple
./script/generate model Person firstname:text lastname:text
 ↪birthdate:date grade_in_school:integer phone_number:text 
 ↪email_address:text
rake db:migrate

At this point, you now have a simple Rails application (using the built-in default database, SQLite) with a single model defined. By creating your model with a generator, you get the following simple unit test file:


require 'test_helper'

class PersonTest < ActiveSupport::TestCase
  # Replace this with your real tests.
  test "the truth" do
    assert true
  end
end

True, you can invoke rake test on this, and the tests will succeed, but that's because the test is completely empty. You can write:

rake test:units

______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState