Behavior Driven, Test Driven, Domain Driven Design
After seeing Greg Youngās demonstrate how to write BDD style tests for CQRS in this videoā-a word of warning though, itās over 6 hours and Iām not quite sure where the testing part startedā-I started working on applying it to my own domain model which uses nCQRS. I also switched from nUnit to MSpec as my preferred tool for testing, partly because it has better syntax and support for BDD. Upon doing so I needed to create a simple base test context class to facilitate the testing. After a couple of refactorings Iām very satisfied with the result and I wanted to share it.
I also think seeing these how these tests work goes a long way towards understanding how CQRS/event sourcing systems work (testing is believing). The generic pattern typically followed when applying BDD to an event sourced CQRS model is as follows:
Given a history of events (the current state of the domain model) When this command is executed (the behavior we want to test) Then the following events should have occurred (the expectations we have for this test)
I think itās worth noting that Iām not necessarily saying that Give/When/Then is the only right way to approach BDD, and Iām aware there is some contention around conforming to this style. However, in this scenario they fit and so it certainly makes sense to use them to describe the tests. However, since Iām going to use MSpec for my tests, which doesnāt support this style of writing or reporting the test cases, I wonāt be conforming to it either and I donāt really think itās of any importance either. All that is really important is how these tests drive our design and expose our use cases. MSpec provides the following conventions for setting up our tests:
Establish is used to provide the context for a test, this is where I set up the historic events and the domain state. Because is used to execute the action under test, in this case we are executing a command for the domain which will be handled by our command handler. It is the way we define our expectations of what should have happened. Iāve created a custom Should extension method to test the event results.
Here is an example of a test I wrote in this style:
public class when_updating_a_feature_for_a_product : domain_context<SetFeaturesForProduct, SetFeaturesForProductHandler>
{
static Product _product;
Establish context = () =>
{
_product = Given<Product>(History.product_created, History.product_feature_added);
ExpectedEvents = 1;
};
Because of = () => When(new SetFeaturesForProduct
{
ProductId = _product.EventSourceId,
Features = new Dictionary<string, object> { {'feature1', 'updated feature value'} }
});
It should_have_updated_the_feature_value = () => Events.ShouldHave<ProductFeatureUpdated>(
x => x.Feature == 'feature1',
x => x.Value == 'updated feature value');
It should_do_nothing_else = () => Events.Count().ShouldEqual(ExpectedEvents);
}
Pretty clear and concise if I do say so myself (and I do). The base class for these tests provides itās own base Establish context which is run first and sets up the scaffolding for nCQRS to execute for the test. Itās generic parameters define the ICommand type and ICommandExecutor<TCommand> that the test will be based on.
Finally we hook into the events using nCQRSā built in delegate handler. Hereās the Gist:
public static class DomainSpecificationExtensions
{
public static void ShouldHave<T>(this IEnumerable<ISourcedEvent> source, params Predicate<T>[] conditions) where T : class, ISourcedEvent
{
T actualEvent = (T) source.FirstOrDefault(x => x is T);
if (actualEvent == null)
throw new SpecificationException(string.Format('{0} did not happen as expected', typeof (T).Name));
actualEvent.ShouldMatch(conditions);
}
public static void ShouldMatch<T>(this T actual, params Predicate<T>[] conditions) {
foreach (var condition in conditions)
{
if (!condition.Invoke(actual))
throw new SpecificationException(string.Format('{0} did not match the condition {1}', typeof(T).Name,
condition.Method.GetMethodBody()));
}
}
}This base class even supports command excution involving multiple aggregate roots. When we call Given() an aggregate root is created, initialized from the event history and any new events are then tracked via the delegate call. Itās also added to the mock UoW class used by the command handler so the handler will be able to load it. It is extremely easy to write consistent, repeatable BDD style tests using this pattern, and because we verify each event and ensure no other events occurred we are testing not only what has happened but also what hasnāt happened, something that is typically very hard to verify.
Reference: Behavior Driven, Test Driven, Domain Driven Design from our NCG partner Chris Nicola at the lucisferre blog.

