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:
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:
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="http://test.host/sessions/new">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.
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_response(those two seem to give me the most headaches, but YMMV).
- Good candidates are other one-parameter
asserts (not counting the message) like
- 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".
inspectmethods when displaying variables etc., its output is most of the time more legible than
- Rails-specific assertions provide sufficiently informative default messages in most cases.