Posted over 5 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.

Background

Consider this test:

Copy
User.last.should be_present

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

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

Solution

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

Copy
User.last.should be_present, 'Could not find a user!'

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

Copy
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:

Copy
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.

Caveats

You can't put custom error messages when comparing equality with ==. For that, you might want to use the uglier eql (note that this is close, but not the same as ==):

Copy
foo.should eql(23), 'Foo is off!'

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

Copy
expect { foo > 23 }.to be_true, 'Foo is off!'

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

Once an application no longer requires constant development, it needs periodic maintenance for stable and secure operation. makandra offers monthly maintenance contracts that let you focus on your business while we make sure the lights stay on.

Owner of this card:

Avatar
Arne Hartherz
Last edit:
almost 3 years ago
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 cookies to improve usability and analyze traffic.
Accept or learn more