Assert Messages Are Not Optional

...and now, in this week's episode of Zero-Friction TDD: Optional Assert messages that aren't optional anyway!

Actually, this piece of advice comes almost directly from the xUnit Test Patterns book, so I was in doubt whether I should post it all, but it bears repeating, and I guess I still have a few things to add.

The various Assert methods all have an overload that takes a message string that is basically just echoed to the Test Results list if the test fails, appended to the assertion's more generic message.

For example, this assertion

 Assert.AreEqual<string>(expectedResult, result, "DoStuff");

will produce this output:

Assert.AreEqual failed. Expected:<ploeh>. Actual:<>. DoStuff 

As there are also overloads available that does not take such a message string, it is tempting to treat it as optional. As far as the compiler is concerned, I might as well have written this:

 Assert.AreEqual<string>(expectedResult, result);

which would have yielded this output:

Assert.AreEqual failed. Expected:<ploeh>. Actual:<>.

Not much of a difference, so it may seem quite redundant to supply this extra message.

Well, not only will I argue that it provides value, I will even go so far as to insist that you should treat it as mandatory. Here's the reason:

When one or more test failures appear in the Test Results window, my eyes naturally seek out the Error Message text, so it's very nice to have all the information I need present in the same context. All I really need is just a small hint that will jog my memory enough so that I know what I did wrong.

Please note that I'm not really talking about using the message in the initial Red/Green/Refactor development cycle. In this phase, I rarely read the test failure text at all - I only register that there was a failure, which was expected, since the code isn't implemented yet.

I'm talking about what happens when you refactor a code base with hundreds of tests. In such cases, I often inadvertently break existing tests, and my eyes immediately seek out the Error Message.

Imagine that this is the error message:

Assert.AreEqual failed. Expected:<ploeh>. Actual:<>.

All this really tells me is that in one of my tests (and I don't know which one yet), something was expected to have the value ploeh, but ended up having no value. That's not a lot to go after, so I will probably have to open the test and read it through to get enough context to know what I broke.

On the other hand, I've experienced that just a little extra message often provides just enough context that I immediately realize what I broke:

Assert.AreEqual failed. Expected:<ploeh>. Actual:<>. DoStuff 

In this case, DoStuff is the name of the method being tested. It may seem hard to believe, but in most cases, this is context enough to help my brain figuring out what went wrong. Keep in mind that the test failure was a result of a code change that I just implemented, so my mind has a lot of context already, and it needs almost no help to make the final connection.

When I first encountered this guidance, I was sceptic, but after having worked with it for some time, I'm not going back. It has increased my productivity while refactoring, because I don't need to investigate failure causes quite as often as I did before.

Most developers dislike having to write this optional message because they feel that they ought to write a long piece of fluent prose. That's not the case: Just write a single cue that can trigger your brain at a later date. Normally, I just write the name of the method or property I'm testing - I find that I can easily do that and still stay in the zone when I'm writing my tests.

You are probably still skeptical, but try it out for a couple of months and see what you think!