Using assert’s message to boost your unit testing productivity

Here’s a quick tip for enhancing your test writing productivity: use assert‘s last parameter, the message. Virtually all assert_... methods accept it. You may have noticed in the docs that the last parameter is always message = nil or message = "". Too bad the docs don’t give examples on how to use this message. So, let me fix that.

* Just a note before we begin: everything here is very basic stuff. Almost newbie level. I suspect most of you already know about it and use it. But sometimes knowing is not enough: you need someone to show you some examples, so you can have your aha! moment. Hence this article.


Let’s start with plain assert. Normally you would use with just a condition that should be true, like that:

assert some_list.empty?

But when it fails, you will only get this message:

<false> is not true.

along with test name, line number or stack trace. This is not very helpful, because it doesn’t give any hints as to why did the test fail? Why wasn’t the list empty? What was inside it? Sometimes you don’t even know what was asserted until you look up the failing line in the editor (this may happen when you have many asserts per test method or your test names aren’t descriptive).

Anyway, it might take some time before you even start looking for the cause of this failure. And if you can’t spot it in the code right away, you’ll probably have to add debugging code to display information that might give you some hints and run the test again.

In the above example the first thing you would most probably like to know are the contents of the list. Why not skip this whole step and have this information displayed anytime the test fails? If you try this:

assert lst.empty?, lst.inspect

the message will be slightly more revealing:

[1, 2].
<false> is not true.

Now you know at least what’s inside the list — in most cases this should give you a strong hint about the cause.

* Another benefit of using this technique is that you don’t have to cleanup the debugging code once you correct the test.


Another example, this time Rails related: probably one of the most frequently used asserts in functional tests is assert_response. When you use it this way:

assert_response :success

the failure message might look like this:

Expected response to be a <:success>, but was <302>

Again, not very helpful. But try this:

assert_response :success, @response.body

and you might get:

<html><body>You are being <a href="">redirected</a>.</body></html>.
Expected response to be a <:success>, but was <302>

A lot better. Judging on the redirection address, we were trying to access a resource that requires login. So, first thing to check is whether our test performs login before accessing the page.

More examples

A couple more examples, hopefully self-explanatory:

assert_nil object, object
assert_nil object, object.inspect
assert_false object, object.inspect
assert_respond_to object, method, object.methods.inspect

# Rails
assert post.valid?, post.errors.full_messages


Of course, there is no point in adding this information to all your asserts. Some of them (e.g. assert_equal) in most cases provide enough information by default. My rules of the thumb are:

  • Always use it with assert and assert_response (those two seem to give me the most headaches, but YMMV).
  • Good candidates are other one-parameter asserts (not counting the message) like assert_nil, assert_false etc.
  • Assertions in complicated test methods.
  • When you have many assertions per test method.
  • When you have already spent some time looking for the cause, add the information that helped you fix the test so you don’t have to do it again.
  • You can display any message you want, e.g. "This fails when somebody tinkered with DontTouchMe class".
  • Use inspect methods when displaying variables etc., its output is most of the time more legible than to_s (the default).
  • Rails-specific assertions provide sufficiently informative default messages in most cases.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: