---
title: Writing matchers for shoulda
teaser:
tags: web,ruby,testing,shoulda
author: Joe Ferris
published_on: 2010-12-16
---

Shoulda provides assertions that allow developers to quickly test common Rails
functionality, such as validations, associations, and controller responses.
These assertions have traditionally been packaged as "macros" - class methods
that generate test methods. For a while now, we've been moving towards matchers
internally to provide that functionality. This allowed RSpec and Test::Unit
users to access the same test assertions with only a thin wrapper. [This past
Spring](https://thoughtbot.com/blog/post/701863189/shoulda-rails3-and-beyond),
we cut out most of the wrapper code by eliminating the "macro" concept and
instead having Test::Unit users access the matchers directly.

We believe it's a waste for users to write the same test assertions twice (once
for RSpec and once for Test::Unit), and now that shoulda supports them directly,
matchers can be the common building blocks for test assertions in both
frameworks.

One question we've frequently seen since switching to matchers is, "how do I
write my own custom macros now?" The short answer is, "you don't: you write a
matcher instead." The long answer is this blog post.

## Old school: macros

If you were going to write a `should_be_instance_of` macro in the old style, you
might do it like this:

    def self.should_be_instance_of(class_name)
      should "be an instance of #{class_name}" do
        assert_equal class_name, subject.class.name
      end
    end

This macro could be used like:

    should_be_instance_of 'User'

This is pretty simple and legible, but it has a few flaws:

* The assertion logic is stuck inside the should block, so it isn't easy to
  reuse in RSpec or in other assertions. Creating macro methods like this
  divides the Test::Unit landscape by making some assertions instance-level
  assertions and others class-level "macros."
* The test name is also stuck in the macro, so you can't write your own more
  meaningful test name. This leads to test names with a "generated" feeling that
  don't adequately describe the intent of the test.
* You'd have to write another macro that's essentially the same if you want the
  negative case (should_not_be_instance_of)
* Although this is a simple case, more complex assertions can be more than a
  hundred lines long. In these cases, you'd want to break them up into multiple
  methods, which is difficult to do in one-off test method generators.
* Macros are difficult to test, because they generate test methods and can't be
  invoked separately

## What's a matcher

The common matcher <abbr title="Application Programming Interface">API</abbr>
shared between RSpec and shoulda involves creating a Ruby object that responds
to four methods:

* `matches?`: returns `true` if the subject matches the expectations for this
  matcher
* `failure message`: `should` uses this message if `matches?` returns `false`
* `negative_failure_message`: `should_not` uses this message if `matches`?
  returns `true`
* `description`: used if a test name is generated from this matcher

The matcher <abbr title="Application Programming Interface">API</abbr> itself is
not a dependency - it's just a specification. All you need to write a matcher is
Ruby.

To write the same macro as a matcher, you might use this code:

    class InstanceOfMatcher
      def initialize(class_name)
        @expected_class_name = class_name
      end

      def matches?(subject)
        @actual_class_name = subject.class.name
        @actual_class_name == @expected_class_name
      end

      def failure_message
        "Expected an instance of #{@expected_class_name}, \
         but got an instance of #{@actual_class_name}"
      end

      def negative_failure_message
        "Didn't expect an instance of #{@expected_class_name}, \
         but got one anyway"
      end

      def description
        "should be an instance of #{@expected_class_name}"
      end
    end

    def be_instance_of(class_name)
      InstanceOfMatcher.new(class_name)
    end

This matcher could be used like:

    # Test::Unit with Shoulda
    should be_instance_of('User')
    should_not be_instance_of('Post')

    # RSpec
    it { should be_instance_of('User') }
    it { should_not be_instance_of('Post') }

The matcher has the following benefits over the macro:

* It's usable from Test::Unit both at the class and instance level
* It's usable from RSpec
* It's a separate class, so breaking out into separate methods (or even more
  classes) is clean and cheap.
* Although this is a simple case, it allows you to expand into private methods
  and other classes if necessary
* You get the negative case without as much duplication
* Because the matcher doesn't generate a test, you can write your own test name
  if you'd like
* Matchers are easier to test, because they're just Ruby objects

## Why the long face

One thing you'll immediately notice is that the matcher for this example is
undeniably longer. Part of that is because an RSpec matcher has more
infrastructure, so a simple matcher is always longer than a macro. However, I
find that most cases are not so simple - otherwise, I wouldn't need to write a
reusable matcher for them.

If you're willing to introduce a dependency on rspec-expectations, you can use
the matcher DSL, which is considerably less verbose for simple cases:
https://github.com/dchelimsky/rspec/wiki/Custom-Matchers

Using the matcher DSL, the above example could be written as:

    RSpec::Matchers.define :be_instance_of do |expected_class_name|
      match do |subject|
        actual_class_name = subject.class.name
        actual_class_name.should == expected_class_name
      end
    end

However, if you want to write matchers that are compatible with both RSpec and
shoulda without adding any dependencies, you'll have to write out the full
class. In order to have as few dependencies as possible, all of shoulda's
built-in matchers are written as concrete classes and methods.

Another thing that should be said is that, although matchers tend to use more
lines than an equivalent assertion or macro, they're frequently less terse, so
they can be easier to read and write despite their length.

## Learn by example

You can find more examples by looking at shoulda itself: https://github.com/thoughtbot/shoulda

The shoulda matchers exercise the matcher concept in just about every way
possible, and there are dozens of examples available. If you have specific
questions about writing or using matchers, you can always ask on the shoulda
mailing list: http://groups.google.com/group/shoulda

If you have existing macros that generate test methods using "should," they'll
continue to work using the shoulda context framework. Nobody will stop you from
writing more, but we highly recommend giving matchers a shot - they're more
flexible, more reusable, and will open your assertions to a wider audience.
