Freigeben über


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!

Comments

  • Anonymous
    December 16, 2008
    PingBack from http://blogs.msdn.com/ploeh/archive/2008/11/13/zero-friction-tdd.aspx

  • Anonymous
    December 17, 2008
    Do you include input parameters, if any, to the assert message? This might provide usefull information as to the cause of the error.

  • Anonymous
    December 17, 2008
    No, never. The default message provided by the assert methods are normally sufficient. E.g. "Assert.AreEqual failed. Expected:<ploeh>. Actual:<>." gives me all the details I need to know what went wrong. The custom message cues me into where and why. It's important to keep in mind that you must not allow yourself to be slowed down, and setting up a format string and passing in parameters would definitely do that.

  • Anonymous
    January 11, 2010
    Instead of making the message string mandatory you might want to consider the unit test method naming standard promoted by Roy Osherove. Method_Scenario_Result If you name your test well you'll get three key bits of information attached to the test that failed which in my mind is a big win.

  • Anonymous
    August 13, 2013
    If you use the name of the method or property you're testing as the assert message, don't you find it problematic when you come to rename the member under test? Automatic refactoring tools like ReSharper (or even Visual Studio) won't change the name in the string.