Posted over 7 years ago. Visible to the public. Repeats. Linked content.

Custom error messages in RSpec or Cucumber steps

Sometimes you have a test expectation but actually want a better error message in case of a failure. Here is how to do that.


Consider this test:

expect(User.last).to be_present

In case of an error, it will fail with a not-so-helpful error message:

expected present? to return true, got false (Spec::Expectations::ExpectationNotMetError)


That can be fixed easily. RSpec expectations allow you to pass an error message like this:

expect(User.last).to be_present, 'Could not find a user!'

Now your test will fail with an actually helpful error message:

Could not find a user! (Spec::Expectations::ExpectationNotMetError)

Note that you may also pass a block, if necessary.

Why is this cool?

One might argue why we would want to have better error messages for test expectations when our tests are supposed to be always passing. Well, what if they don't pass at some point? Have you ever had to dig into a test just to find out why it was failing? If that test had actually told what it was expecting, you did not have to do it.

Even more so: Consider an expectation that is actually more complex than the one above. Maybe you are looking at an array of items and want to check only a subset of them. Instead of a simple true/false error message, you could also have a message that shows what the expectation was working on, and what failed:

Found 0 instead of 2 matching events: [] All events: [{"gtm.start"=>1234567890, "event"=>"gtm.js"}, {"event"=>"gtm.dom"}, {"event"=>"gtm.load"}] (Spec::Expectations::ExpectationNotMetError)

And the best thing: Since you are using RSpec expectations in your Cucumber steps most of the time, you can do the same there.


If you are using the legacy should syntax, you can't put custom error messages when comparing equality with ==. For that, you might want to use eq instead:

foo.should == 42, 'Not a valid answer' # does NOT work foo.should eq(42), 'Not a valid answer'

Inequality is trickier, and uglier. You might want to wrap your expectation and compare against a boolean, maybe like this:

expect { foo > 23 }.to be_true, 'Not a valid answer'

If things get too tricky, you could be better off writing a custom RSpec matcher.

Your development team has a full backlog of feature requests, chores and refactoring coupled with deadlines? We are familiar with that. With our "DevOps as a Service" offering, we support developer teams with infrastructure and operations expertise.

Owner of this card:

Arne Hartherz
Last edit:
3 months ago
by Arne Hartherz
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more