Pain reduction: creating ductile tests

time to read 2 min | 310 words

Take a look at this test:

[Test]
public void When_asking_for_latest_webcast_will_not_consider_webcasts_published_in_the_future()
{
	var webcast = new Webcast { Name = "test", PublishDate = DateTime.Now.AddDays(-2) };
	With.Transaction(() => webcastRepository.Save(webcast));
	var webcast2 = new Webcast { Name = "test", PublishDate = DateTime.Now.AddDays(2) };
	With.Transaction(() => webcastRepository.Save(webcast2));
	Assert.AreEqual(webcast.Id, webcastRepository.GetLatest().Id);
}

It looks like a valid test, doesn't it? It has a huge problem. It is brittle.

I just added a new non null property, and all the tests broke. I started to add the new property value to the test, before I realize what I was doing. I run into a friction point, and I was trying to cover it with code. Next time I would add such a property, I would run into the same problem.

This is unacceptable.

The standard solution for this is to create a factory for this, or use an Object Mother. This was never something that I was fond of. I always need more flexibility than I can usually get from it, and I hate building builders, that is so boring.

Turn out, I can eat the cake and keep it.

I created the following test class:

[ActiveRecord("Webcasts")]
public class TestableWebcast : Webcast
{
	public TestabbleWebcast()
	{
		Name = "Test name";
		Description = "Test description";
	}
}

And now the test change to:

[Test]
public void When_asking_for_latest_webcast_will_not_consider_webcasts_published_in_the_future()
{
	var webcast = new TestableWebcast { PublishDate = DateTime.Now.AddDays(-2) };
	With.Transaction(() => webcastRepository.Save(webcast));
	var webcast2 = new TestableWebcast { PublishDate = DateTime.Now.AddDays(2) };
	With.Transaction(() => webcastRepository.Save(webcast2));
	Assert.AreEqual(webcast.Id, webcastRepository.GetLatest().Id);
}

I get to keep the nice object initializer syntax, and I even get more clarity, since I can now specify only the properties that I am actually interested in.

The only annoying thing is that I have to define the TestableWebcast as an entity as well, but I can live with it.