About Me

Training

Develop With Passion® - Developer Bootcamp

Subscribe

How I'm Currently Writing My BDD Style Tests - Part 2

Written December 22, 2008 at 14:29 MST Tagged c sharp and programming

We left off in part 1 with an example of a test written using my current style and I finished off outlining the skeleton for one of the base classes that shields the actual Concern classes from a lot of noisy test related nomenclature.
In this post I am going to break down the responsibilities of the “an_observations_basic_set_of_behaviours” class. For a quick reminder, here is the skeleton outline of the class:

[Observations]

public abstract class an_observations_set_of_basic_behaviours

{

static protected IDictionary<Type, object> dependencies;

static Exception exception_thrown_while_the_sut_performed_its_work;

static protected Action behaviour_of_the_sut;

[SetUp]

public void setup() {}

void prepare_to_make_an_observation() {}

[TearDown]

public void tear_down() {}

after_all_observations a = () => dependencies.Clear();

ICommand build_command_chain() {}

void run_action() {}

protected virtual void initialize_the_sut() {}

static public void doing(Action action) {}

static protected Exception exception_thrown_by_the_sut

{

get { }

}

static Exception get_exception_throw_by(Action action) {}

static protected object an(Type type) {}

static protected InterfaceType an() where InterfaceType : class {}

}

}


Let’s start off by discussing the fields:

static protected IDictionary<Type, object> dependencies;


  • This field is hopefully pretty self explanatory. It is a dictionary that will contain any direct dependencies of the SUT. In most of my apps I tend to favour Constructor based DI so, this dictionary basically contains the set of objects (mocks and/or reals) that the sut will depend on. How this gets populated will be discussed later.

static Exception exception_thrown_while_the_sut_performed_its_work;

static protected Action behaviour_of_the_sut;


That takes care of the first set of fields, lets move on to a method that should look very familiar to MbUnit/NUnit people:

[SetUp]

public void setup()

{

exception_thrown_while_the_sut_performed_its_work = null;

dependencies = new Dictionary<Type, object>();

prepare_to_make_an_observation();

}

This is a traditional MbUnit setup method. Because it is decorated with the SetUp attribute, all of the code in this method will get run once before each observation (test). Essentially this method is used to reset stateful fields, this is not that interesting. The guts of setup happen in the following method:

void prepare_to_make_an_observationjjj()

{

run_action<context>();

initialize_the_sut();

run_action<after_the_sut_has_been_initialized>();

run_action<because>();

}


In this base class the initialize_the_sut method has an empty implementation. The prepare_to_make_an_observation method leverages a hook method (initialize_the_sut) that can be leveraged (it will be by an_observation_for_an_instance_sut). In the base class, it is a virtual method with no implementation. As you can see, this method is responsibility for performing the following actions before an observation can be made:
Again this is a small little method that basically serves as a driver for prepping the way to be able to make observations. By the time we actually enter an observation in our actual fixtures, the SUT has already performed its work!!
Now I am sure you are wondering what the deal is with the run_action method? Here is the signature for the run_action method:

void run_action()


This method is a generic method that accepts a delegate type as its generic argument. Again this is a convention that is understood by the naming of the generic parameter. You can’t place constraints on a generic method that constrain the Generic argument to be assignable from a delegate (of course, you can do this with a guard clause). Here are the different delegate signatures that I defined for use in the test-harnesses:

public delegate void context();


public delegate void after_the_sut_has_been_initialized();


public delegate void because();


public delegate void after_each_observation();

You may be wondering why I did not just use the plain old action delegate as opposed to creating discrete delegate types. This is so the driver class (this one we are examining) has a clearer way of differentiation between the different delegates. Without the named delegate types, I would have to resort to following a convention for the name I assigned to a field for an Action delegate (messy, messy).
Here is the full implementation of the run_action method:

void run_action()

{

build_command_chain().run();

}

Once again, this method is pretty simple as it is really delegating its responsibility to whatever gets created by the build_command_chain method. So lets dive into the full body of this method, as this is really where the majority of the work is being done:

ICommand build_command_chain()

{

var actions = new Stack<ICommand>();

var current_class = GetType();

while (current_class.is_a_concern_type())

{

actions.Push(new DelegateFieldInvocation(typeof (DelegateType), this, current_class));

current_class = current_class.BaseType;

}

return actions.as_command_chain();

}

So what is going on here. Take a look at this test one more time as it will give you a good visual as to what is going on:

[Concern(typeof (MappingStep<,,>))]

public class when_an_expression_mapping_step_is_told_to_run :

concern_for_mapping_step

{

static SomeSourceObject item;

static SomeDestinationObject destination;

static string name;

context c = () =>

{

item = new SomeSourceObject();

name = "JP";

destination = new SomeDestinationObject();

source_evaluator.Stub(x => x.evaluate_against(item)).Return(name);

};

because b = () => sut.map(item, destination);

[Observation]

public void should_run_the_target_evaluator_passing_it_the_information_retrieved_from_evaluating_the_source()

{

target_action.was_told_to(x => x.act_against(destination, name));

}

}


I chose not to also put in this Concerns base class, the only important thing to remember about the “concern_for_mapping_step” is that it also has its own context block :

context c = () =>

{

target_action = the_dependency<ITargetAction<SomeDestinationObject, string>>();

source_evaluator = the_dependency<ISourceEvaluator<SomeSourceObject, string>>();

};

It is important to remember that the “an_observations_basic_set_of_behaviours” class is the test driver. Here is the inheritance hierarchy for this current test fixture:


At any point in the chain (starting from the top, working down) each level could have its own context to run. The run_action method is responsible for walking the inheritance hierarchy of a particular concern and building a chain of “commands” for a particular delegate type. Once the command chain has been build, the chain can be executed in the right order (from top to bottom) to ensure that any prior context in a base class has been established before a subclass runs. If you are already thinking, could he not have done the same thing with abstract/virtual methods. Yes. When I initially started down that route, I kept getting stung by forgetting to call back into the base method. By now having to worry about calling the base method prior to doing your own work, you as a developer can just focus on the context that is applicable to a particular test. You can do this, as the driver class is responsible for ensuring blocks run in the order they are supposed to run. Without the driver class, all the fields that have lambdas assigned to them would be useless as they are just sitting there waiting to be invoked.
At the end of the while loop in the build_command_chain method there will be a stack (I chose stack as it is a LIFO structure, which is perfect for walking a class hierarchy, as when the last item is added – the base class, I can just start popping items off and they will be in the right order, ending with the ultimate test class itself). The stack itself is being used to store a set of ICommand implementations. Here is the ICommand interface:

public interface ICommand

{

void run();

}

This is a pretty stock interface that I have used for years. The uses are endless!! How does the loop know when to end? What is with the following method?:

current_class.is_a_concern_type()

The field current_class is of type Type. The is_a_concern_type method is a local extension method that has the following implementation:

static public bool is_a_concern_type(this Type type)

{

return typeof (an_observations_set_of_basic_behaviours)

.IsAssignableFrom(type);

}

This method just adds a bit of readability (from the point of usage, which is a huge bonus of extension methods) and ensures that we wont worry about putting anything that is not either a derivative of an_observations_set_of_basic_behaviours or the an_observations_set_of_basic_behaviours type itself on the stack (it will always be the top item on the stack at the end of the traversal).
So lets explore the line that does the grunt work:

actions.Push(new DelegateFieldInvocation(typeof (DelegateType), this, current_class));

Keep in mind that the actions field is a stack of ICommand. It stands to reason that the DelegateFieldInvocation class is an ICommand implementation. Which it is. The DelegateFieldInvocation class takes in its constuctor a delegate type to scour for, an instance to act against (always this), and finally the particular type to reflect against (this will change as we continue to walk up the inheritance hierarchy). Here is the implementation of the DelegateFieldInvocation:

public class DelegateFieldInvocation : ICommand

{

const BindingFlags probing_flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;

Type delegate_type;

readonly object instance;

IEnumerable<FieldInfo> fields;

public DelegateFieldInvocation(Type delegate_type, object instance, Type current_type)

{

fields = current_type.GetFields(probing_flags);

this.delegate_type = delegate_type;

this.instance = instance;

}

public void run()

{

all_fields_of_the_target_delegate_type().each(x => x.GetValue(instance).downcast_to<Delegate>().DynamicInvoke());

}

IEnumerable<FieldInfo> all_fields_of_the_target_delegate_type()

{

return fields.Where(x => x.FieldType.Equals(delegate_type));

}

}

All this command does in its run implementation is scour all of the fields in the “current_type” and filters them to look for only fields of the certain delegate type being searched for. Once the particular delegate type is found, we get the value of the field using the instance:

x.GetValue(instance).downcast_to<Delegate>()


downcast_to is just a utility extension method to do casting. At this point we have an actual reference to the delegate. With that, because we know (again by convention) that all of the delegate types we are working with are void with no arguments, they can just be invoked by using the DynamicInvoke method that lives on the delegate class. Again, the beauty of the command pattern allows this command to be queued up with all the information that it needs, and then it can simply perform it when it is told to run.
Of course, the build_command_chain ends with this line:

return actions.as_command_chain();

All that this method does is return a Composite of commands that when told to run, will run each of the commands that it is composed with (we’ll dive into that at a later date). So back up in the run_action method:

build_command_chain().run();

It should now be clear to see that the run() method is invoked on the Composite, that will cause all of the commands to run in sequence. In the case of run_action it will cause a Composite command to be built that is composed of commands to run “context” delegates from the Grandparent down to the actual Concern itself.
For clarification, look again at how the run_action method is used:

void prepare_to_make_an_observation()

{

run_action<context>();

initialize_the_sut();

run_action<after_the_sut_has_been_initialized>();

run_action<because>();

}


The other calls to run action simply walk down the hierarchy invoking the appropriate delegate fields that may or may not be present in the actual test classes. The because block is the behaviour we are invoking of our system under test. In the case of the test we first examined:

because b = () => sut.map(item, destination);


For the design pattern aware, you will have already realized that the prepare_to_make_an_observation method (along with the use of delegate fields that can be defined at any level of the hierarchy) is just a specialization of the template method pattern, the main difference being that subclasses do not provide their behaviour by overriding abstract methods, rather they just simply have to define fields of a certain delegate type, that contain the code that will be invoked dynamically by the base class using reflection!!
That is enough for now, we’ll carry on the drilldown in the next part!!
Develop With Passion!!