About Me

Training

Develop With Passion® - Developer Bootcamp

Subscribe

Test examples with MBUnit and jpboodhoo.bdd

Written January 27, 2009 at 06:08 MST Tagged c sharp and programming

The other day I placed a library up on assembla that I use as a place to store my current set of conventions on writing unit tests. My current flavour of testing focuses on the use of BDD to emphasize context and behaviour of a particular SUT (System under test) that I am exercising.
This post is not about detailing my current thinking on BDD, more to demonstrate some ways that you can use the very small framework in conjunction with MBUnit to remove a lot of cruft from your tests. To that end, the following are some sample tests written to demonstrate different aspects of the library:
1) Adding two numbers (without a because block):

public class when_adding_2_numbers_together : observations_for_a_static_sut

{

[Observation]

public void should_result_in_the_sum_of_the_2_numbers()

{

(2 + 2).should_be_equal_to(4);

}

}

Notice that the class simply inherits from a class named observations_for_a_static_sut. This is the base class you will use when you are either testing a static class, or (as in this case) you are simply writing a quick inline test.
2) Adding two numbers with a because block (the because block is meant to focus your eyes to the actual behaviour you are exercising:

public class when_adding_2_numbers_together : observations_for_a_static_sut

{

static int result;

because b = () =>

{

result = 2 + 2;

};

[Observation]

public void should_result_in_the_sum_of_the_2_numbers()

{

result.should_be_equal_to(4);

}

}


The behaviour being exercises is placed inside of a anonymous method block assigned to a delegate type (because). It is also important to note that the field is static.
Let’s look at a slightly more involved test that has some dependencies, a factory method for the system under test, etc. Here is the start:

[Concern(typeof (DatabaseGateway))]

public class when_retrieving_a_set_of_rows_based_on_a_query : observations_for_a_sut_without_a_contract<DatabaseGateway>

{

static IEnumerable<DataRow> result;

static IQuery query;

static IDatabaseConnectionFactory connection_factory;

static IDatabaseConnection connection;

static IDbCommand command;

static IDataReader reader;

context c = () =>

{

connection_factory = an<IDatabaseConnectionFactory>();

query = an<IQuery>();

connection = an<IDatabaseConnection>();

command = an<IDbCommand>();

reader = an<IDataReader>();

connection_factory.Stub(x => x.create()).Return(connection);

connection.Stub(x => x.create_to_run(query)).Return(command);

command.Stub(x => x.ExecuteReader()).Return(reader);

};

because b = () =>

{

result = sut.get_rows_matching(query);

result.force_traversal();

};

[Observation]

public void should_leverage_db_infrastructure_to_return_a_set_of_rows_from_the_db()

{

result.should_not_be_null();

}

[Observation]

public void should_dispose_the_appropriate_items()

{

connection.was_told_to(x => x.Dispose());

}

public override DatabaseGateway create_sut()

{

return new DatabaseGateway(connection_factory);

}

}


Let’s start by taking a look at the context block:

context c = () =>

{

connection_factory = an<IDatabaseConnectionFactory>();

query = an<IQuery>();

connection = an<IDatabaseConnection>();

command = an<IDbCommand>();

reader = an<IDataReader>();

connection_factory.Stub(x => x.create()).Return(connection);

connection.Stub(x => x.create_to_run(query)).Return(command);

command.Stub(x => x.ExecuteReader()).Return(reader);

};

In this block I define all of the dependencies that are going to come into play during the test. The “an” method, is a generic method that lives on the base class, which basically creates a mock of the contract in question. It carries on to setup return values for method calls that will be leveraged during the course of the SUT doing its work. Unfortunately, it is hard to identify which mocks are direct dependencies of the sut and which are collaborators. It is only when you look at the factory method for the system under test:

public override DatabaseGateway create_sut()

{

return new DatabaseGateway(connection_factory);

}

Here it is evident that the direct dependency of the DatabaseGateway is the connection_factory (IDatabaseConnectionFactory). The because block highlights the behaviour being tested:

because b = () =>

{

result = sut.get_rows_matching(query);

result.force_traversal();

};


The force_traversal method is a utility method that forces the traversal of an enumerable. It is necessary as the implementation of the method under test uses deferred execution by nature of leveraging the yield keyword and returning an IEnumerable. Here is the implementation of the class under test:

public class DatabaseGateway

{

IDatabaseConnectionFactory connection_factory;

public DatabaseGateway(IDatabaseConnectionFactory connection_factory)

{

this.connection_factory = connection_factory;

}

public IEnumerable<DataRow> get_rows_matching(IQuery query)

{

var table = new DataTable();

using (var connection = connection_factory.create())

using (var command = connection.create_to_run(query))

using (var reader = command.ExecuteReader())

{

table.Load(reader);

}

foreach (DataRow row in table.Rows) yield return row;

}

}


Let’s now show the exact same test written with the minimum amount of plumbing code that is necessary:

[Concern(typeof (DatabaseGateway))]

public class when_retrieving_a_set_of_rows_based_on_a_query : observations_for_a_sut_without_a_contract<DatabaseGateway>

{

static IEnumerable<DataRow> result;

context c = () =>

{

the_dependency<IDatabaseConnectionFactory>().Stub(x => x.create()).Return(the_dependency<IDatabaseConnection>());

the_dependency<IDatabaseConnection>().Stub(x => x.create_to_run(the_dependency<IQuery>())).Return(the_dependency<IDbCommand>());

the_dependency<IDbCommand>().Stub(x => x.ExecuteReader()).Return(the_dependency<IDataReader>());

};

because b = () =>

{

result = sut.get_rows_matching(the_dependency<IQuery>());

result.force_traversal();

};

[Observation]

public void should_leverage_db_infrastructure_to_return_a_set_of_rows_from_the_db()

{

result.should_not_be_null();

}

[Observation]

public void should_dispose_the_appropriate_items()

{

the_dependency<IDatabaseConnection>().was_told_to(x => x.Dispose());

}

}

The factory method has been removed along with the fields to reference the dependencies that come into play. For readability, I think this approach loses out, so this last way is the way I would finish up with:

[Concern(typeof (DatabaseGateway))]

public class when_retrieving_a_set_of_rows_based_on_a_query : observations_for_a_sut_without_a_contract<DatabaseGateway>

{

static IEnumerable<DataRow> result;

static IQuery query;

static IDatabaseConnectionFactory connection_factory;

static IDatabaseConnection connection;

static IDbCommand command;

static IDataReader reader;

context c = () =>

{

connection_factory = the_dependency<IDatabaseConnectionFactory>();

query = an<IQuery>();

connection = an<IDatabaseConnection>();

command = an<IDbCommand>();

reader = an<IDataReader>();

connection_factory.Stub(x => x.create()).Return(connection);

connection.Stub(x => x.create_to_run(query)).Return(command);

command.Stub(x => x.ExecuteReader()).Return(reader);

};

because b = () =>

{

result = sut.get_rows_matching(query);

result.force_traversal();

};

[Observation]

public void should_leverage_db_infrastructure_to_return_a_set_of_rows_from_the_db()

{

result.should_not_be_null();

}

[Observation]

public void should_dispose_the_appropriate_items()

{

connection.was_told_to(x => x.Dispose());

}

}


This tests reintroduces the fields to store the mocks. It still removes the factory method, and it uses the following two different methods:
to differentiate between a constructor depedency and a mock that happens to come into play while collaborating with that dependency.
There are lots of other things you can do, and I will post more examples as requests come in!!

Develop With Passion!!