TDD++

TDD matters, it is a thing which should be definitely accepted. But during typical development with TDD framework such a NUnit we could meet a lot of issues. Some of them are listed below:

  • which object/class/method is really connected with particular test
  • what should be a part of test method body
  • how many tests should cover a file for testing particular thing
  • what should be the name of test file, test method
  • how we should group repeatable code in our tests to keep them clear and simple
  • and more, and more

After reading article about some BDD way of creating tests (http://elegantcode.com/2008/10/25/refining-contextspecification-bdd-using-rhino-mocks-35/) I changed my own way of creating unit tests. Btw, I recommend you a lecture!

I simplified ‘framework’ for writing unit tests to one class:

public abstract class InstanceSpecification<TSubjectUnderTest>
{
	[SetUp]
	public virtual void BaseSetUp()
	{
		Establish_context();
		Initialize_subject_under_test();
		Because();
	}

	[TearDown]
	public virtual void BaseTearDown()
	{
		Dispose_context();
	}

	[DebuggerStepThrough]
	protected virtual void Establish_context() { }

	[DebuggerStepThrough]
	protected virtual void Because() { }

	[DebuggerStepThrough]
	protected virtual void Dispose_context() { }

	[DebuggerStepThrough]
	protected virtual void Initialize_subject_under_test()
	{
		SubjectUnderTest = Create_subject_under_test();
	}

	protected abstract TSubjectUnderTest Create_subject_under_test();

	protected TSubjectUnderTest SubjectUnderTest { get; private set; }
}

What we have here is nothing more than just instance specification template. Unit tests file which will be based on that template could significantly help us in finding solution for mentioned problems. Why? Before I will answer on that question we should see an example of using that. The example cover some unit tests that could be written for Add() method of List<T> class. Below of that we will find the answers:

public class when_we_adding_new_item_to_list : InstanceSpecification<IList<string>>
{
	protected const string SampleValue = "value";

	protected override IList<string> Create_subject_under_test()
	{
		return new List<string>();
	}

	protected override void Because()
	{
		SubjectUnderTest.Add(SampleValue);
	}

	[Test]
	public void it_should_have_changed_count()
	{
		Assert.That(SubjectUnderTest.Count, Is.EqualTo(1));
	}

	[Test]
	public void then_after_adding_another_item_count_should_be_greater()
	{
		SubjectUnderTest.Add(SampleValue);
		Assert.That(SubjectUnderTest.Count, Is.EqualTo(2));
	}

	[Test]
	public void then_after_adding_any_number_of_items_count_should_be_correct()
	{
		for (var i = 0; i < 1000; i++)
			SubjectUnderTest.Add(SampleValue);

		Assert.That(SubjectUnderTest, Has.Count.EqualTo(1001));
	}

	[Test]
	public void it_should_return_object_with_the_same_value()
	{
		Assert.That(SubjectUnderTest[0], Is.EqualTo(SampleValue));
	}
}

Benefits:

  • we specify exactly one object/class/interface/method which will be tested – generics will describe tested class/interface, method Create_subject_under_test describes the creation of object (instance), and method Because the particular method which will be interested for us in this file
  • for one class/interface we can specify typed instance specification like ListInstanceSpecification which allows us to group common code in one place. Additionally we have still clear tests which are easy to read
  • standardization, standardization and once again standardization, we have common way and places to put logic connected with unit test context establishment, creation of subject under test and for the test’s heart – invoking method after which we could test the instance state or results
  • easy way to named unit test file (when_we_use_<instance_specification_class>_to_<method_invoked_in_because_part>) and unit tests (it_should_<expected_state_of_instance_or_expected_result)
  • one interesting thing per unit test file. Some guys doesn’t agree with this idea but for me it works greatly, especially when it is connected with proper directories structure

For me, it works really good. Probably I will never go back to the old way of creating unit tests. Maybe in the future moving to some pure BDD library will be a better idea? We will see…

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s