At the Forge - Testing Rails Applications with Shoulda

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

Already, you probably can see how Shoulda macros can reduce the amount of code you need to write. Shoulda also provides an RSpec-like facility that makes it possible to name tests using strings, rather than method names. Granted, this is now included in Test::Unit, albeit using a slightly different syntax. But, you can define tests using the should keyword, rather than test, which adds a bit of readability—especially when used in conjunction with contexts, which I describe below.

Here, I create a single method in the model, fullname, which returns the concatenation of the person's first and last name:

def fullname  # added to app/models/person.rb
  "#{firstname} #{lastname}"
end

Next, I add a new test:

should "return the concatenation of the first and last name" do
  person = Person.new(:firstname => "First",
                      :lastname => "Last",
                      :email_address => "email@example.com")

  assert_equal person.fullname, "First Last"
end

Now, there's nothing wrong with this test. It not only passes, but it also does a good job of checking that you are getting the right values back. Maybe it's just me, but I sometimes end up with very long lists of tests and end up categorizing them using comments inside the test file. Shoulda provides contexts that let you group tests within your file, using code rather than comments. It's obviously a bit silly to have a single context and a single test, but as with many things in the TDD/BDD world, it's worth doing things right even from the beginning, because you know that your codebase will grow over time, making it difficult to organize things correctly.

To define a context, you merely write:

context "Defined methods" do
    # "should" blocks go here
end

In other words, you now can rewrite the test block as:

context "Defined methods" do
    should "return the concatenation of the first and last name" do
        person = Person.new(:firstname => "First",
                      :lastname => "Last",
                      :email_address => "email@example.com")

        assert_equal person.fullname, "First Last"
    end
end

With a context block and a should block, you now can read your test as, “Defined methods should return the concatenation of the first and last name.” It's not the most amazing description in the world, but it's not a bad start. And besides, now you can add additional should blocks to test other defined methods.

A context may contain other contexts, as well as should blocks. This means that if you have a particularly complicated model you want to test, you can have a hierarchy of contexts, with should blocks at the bottom.

Moreover, using a context block means that you can write a setup block, which defines variables and otherwise allocates resources that will be used inside a should block. You could, for instance, now write:

context "Defined methods" do
  setup do
    @person = Person.new(:firstname => "First",
                         :lastname => "Last",
                         :email_address => "email@example.com")

  end

  should "return the concatenation of the first and last name" do
    assert_equal @person.fullname, "#{@person.firstname}
    ↪#{@person.lastname}"
  end
end

As you can see, variables that are shared between a setup block and a should block need to be instance variables, their names preceded by an @ sign.

When a test is invoked, all the setup blocks within all of its surrounding contexts are invoked first. This means if a should block is within three nested contexts, and if each of those contexts has its own setup block, all three will fire before the test is executed.

Conclusion

If you are using Test::Unit to test your Ruby on Rails application, Shoulda is a natural fit, allowing you to write a large number of common tests using flexible, easy-to-read macros. In this article, I cover uses of Shoulda only for ActiveRecord models; other parts of Shoulda work with controller tests, providing additional features that can be of use for testers.

From my perspective, using Shoulda is a no-brainer. I have used it in a number of projects already and found that it further lowered the threshold to TDD/BDD, helping make my code that much more reliable. If you are new to testing, Shoulda is a great way to get started, providing an easy way to increase the stability and correctness of your code. All in all, Shoulda is a great resource for Ruby programmers in general and Rails programmers in particular.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix