Mark Needham

Thoughts on Software Development

TDD: Testing collections

with 5 comments

I’ve been watching Kent Beck’s TDD screencasts and in the 3rd episode he reminded me of a mistake I used to make when I was first learning how to test drive code.

The mistake happens when testing collections and I would write a test which would pass even if the collection had nothing in it.

The code would look something like this:

[Test]
public void SomeTestOfACollection()
{
	var someObject = new Object();
	var aCollection = someObject.Collection;
 
	for(var anItem : aCollection)
	{
		Assert.That(anItem.Value, Is.EqualTo(...));
	}
}

If the collection returned by someObject is empty then the test will still pass because there is no assertion to deal with that situation coming up.

In Kent’s example he is using an iterator rather than a collection so he creates a local ‘count’ variable which he increments inside the for loop and then writes an assertion outside the loop that the ‘count’ variable has a certain value.

In my example we can just check that the length of the collection is non zero before we iterate through it.

[Test]
public void SomeTestOfACollection()
{
	var someObject = new Object();
	var aCollection = someObject.Collection;
 
	Assert.That(aCollection.Count(), Is.GreaterThan(0));
	for(var anItem : aCollection)
	{
		Assert.That(anItem.Value, Is.EqualTo(...));
	}
}

It’s a relatively simple problem to fix but it’s certainly one that’s caught me out before!

Be Sociable, Share!

Written by Mark Needham

July 28th, 2010 at 6:05 am

Posted in Testing

Tagged with

  • Typically I would expect a test to fail if it ran with no assertion. Some kind of safety which we can get from the testing f/w we are using.

    But still using the guard assertion before validation of the assertion makes the intent explicit 🙂

    –Sai

  • Do frameworks in the world of Ruby allow you to have a test fail if there’s no assertion? I haven’t seen anything like that in the .NET world so far.

  • Aren’t we really asserting two different things
    1. The collection is not empty
    2. The elements in the collection are certain values

    So shouldn’t this then be two different tests. Though you would still have the one method that would still pass if the collection was empty.

  • I prefer that the testing framework provides assertions for checking whether the collection or array contains some values. There are six types of containment assertions which cover practically all of my use cases: contains, contains all, contains any, contains exactly, contains in order, contains in partial order. See for example http://www.jdave.org/documentation.html#containments (the first framework I used) and http://github.com/orfjackal/gospec/blob/release/examples/expectation_syntax_test.go#L73-90 (a framework I wrote).

  • Philip Schwarz

    Hi all,

    in Java, using Hamcrest, it is possible to do the following:

    List threes = Arrays.asList(3,3,3);
    List oneTwoThree = Arrays.asList(1,2,3);
    List noThrees = Arrays.asList(0,1,2);

    assertThat(threes, everyItem(is(equalTo(3))));
    assertThat(oneTwoThree,not(everyItem(is(equalTo(3))));
    assertThat(noThrees, everyItem(is(not(equalTo(3)))));

    although to get this to work we have to introduce the following method to deal with Generics issues

    @SuppressWarnings(“unchecked”)
    private Matcher equalTo(Integer i)
    { return(Matcher)org.hamcrest.Matchers.equalTo(i);
    }