Mark Needham

Thoughts on Software Development

TDD: Keeping assertions clear

with 7 comments

Something which I noticed was a problem with the first example test that I provided in my post about API readability and testability is that the assertion we are making is not that great.

[Test]
public void ShouldConstructModelForSomeSituation()
{
	Assert.AreEqual(DateTime.Today.ToDisplayFormat(), model.SomeDate()); 
}

It's not really obvious what the expected result is supposed to be except that it should be the 'DisplayFormat'. If that fails then we'll need to navigate to the 'ToDisplayFormat' method to work out what that method does.

I think it should be possible to immediately know why a test failed so that we can address the problem straight away without too much investigation.

In this example we changed the way the code was working which coincidentally allowed us to make the assertion more obvious.

[Test]
public void ShouldConstructModelForSomeSituation()
{
	Assert.AreEqual("10 Oct 2009", model.SomeDate()); 
}

Erik pointed out another example of this a few weeks ago while we were working on some HTML helper code.

The tests in question looked roughly like this:

[Test]
public void ShouldConstructReadOnlyValue()
{
	var readOnlyValue = new HtmlHelper().ReadOnlyValue("someId", "someValue", 'someTextValue');
 
	...
	var expectedValue = new TestHtmlBuilder().AddLabel("someId", "someTextValue").AddHiddenField("someId", "someValue").Build();
 
	Assert.AreEqual(expectedValue, readOnlyValue);
}

The test reads reasonably nicely and it's fairly obvious what it is we're testing for.

The problem here is that we've hidden away our expectation and in this case we actually found out that the 'TestHtmlBuilder' had extra spaces in some places so all our assertions were incorrect and we didn't even know!

In addition we end up duplicating the logic that the 'HtmlHelper' is doing if we create test assertion helpers like these.

[Test]
public void ShouldConstructReadOnlyValue()
{
	var readOnlyValue = new HtmlHelper().ReadOnlyValue("someId", "someValue", 'someTextValue');
 
	...
	var expectedValue = @"<input type=""hidden"" id=""someId"" value=""someId"" /><label for=""someId"">someValue</label>";
 
	Assert.AreEqual(expectedValue, readOnlyValue);
}

The new test doesn't look as clean as the old one but the assertion is much more obvious so if it fails then we can quickly work out why.

Written by Mark Needham

October 10th, 2009 at 11:07 am

Posted in Testing

Tagged with

7 Responses to 'TDD: Keeping assertions clear'

Subscribe to comments with RSS or TrackBack to 'TDD: Keeping assertions clear'.

  1. in short, are you trying to be less dependent on the methods that provide expected values and replace them with static data?

    skim

    12 Oct 09 at 3:25 pm

  2. this wouldn't necessarily be replacing real methods with stubs, but rather using static data for state verification (read martin fowler's mocks aren't stubs post).

    skim

    12 Oct 09 at 3:31 pm

  3. [...] TDD: Keeping assertions clear – Mark Needham talks about the importance of keeping assertions clear so if is obvious why a test is failing [...]

  4. @skim – In this case I wasn't referring specifically to mocks/stubs but certainly making the expectations more static in the sense that you can know exactly what they are just by looking at the test.

    Mark Needham

    12 Oct 09 at 7:57 pm

  5. my second comment should have said that I read martin fowler's article, not for you to read it (past tense).

    thanks for the article. this is giving me a better understanding how to create assertions

    :)

    skim

    13 Oct 09 at 4:12 am

  6. @skim – oh ok got a bit confused! I haven't read it for a while – will check it out for the state verfication stuff though. Mostly read it just for the comparison the last time.

    Mark Needham

    13 Oct 09 at 7:05 am

  7. Thats why they say expect literals in test :)

    Sai Venkat

    20 Oct 09 at 1:38 am

Leave a Reply