CQRS architecture seems to be very popular. And I’m on that wave as well. In short CQRS is separating all read-actions from write-actions. And you have different classes for reading and writing. Queries for reading. Commands for writing.

For queries you would have IQuery and IQueryHandler interfaces:

public interface IQuery<out TResult>
{
}

public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}

For command you would have very similar set of interfaces:

public interface ICommand
{
}

public interface ICommandHandler<in TCommand>
{
    void Handle(TCommand command);
}

This guy here talks about queries and mediator in more details, and I suggest you go read it if you want to use CQRS in your systems. But for cases like this where you have too many queries you should use Mediator pattern, where query handler is resolved inside of the mediator.

Mediator basically hides all the dependencies on query and command handlers from consumers: resolves the classes directly from DI container. The problem there that you might miss some handlers for some queries and then exceptions will fly at runtime.

To avoid that I suggest you put a test around that: check that all queries have all handlers:

class AllQueriesHaveHandlers
{
    [Test]
    public void AllQueries_Always_HaveHandlers()
    {
        //Arrange
        var allQueryTypes = Assembly.GetAssembly(typeof(IQuery<>)).GetTypes()
                .Where(t => t.IsClass && t.IsClosedTypeOf(typeof(IQuery<>)))
                .ToList();

        var allHandlerTypes = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .Where(t => t.IsClass && t.IsClosedTypeOf(typeof(IQueryHandler<,>)))
            .SelectMany(t => t.GetInterfaces())
            .ToList();

        // Sanity checks
        Assert.IsNotEmpty(allQueryTypes);
        Assert.IsNotEmpty(allHandlerTypes);

        // Act
        var missingHandlers = new List<Type>();
        foreach (var queryType in allQueryTypes)
        {
            var resultType = queryType.GetInterfaces()
                .Single(i => i.IsClosedTypeOf(typeof(IQuery<>)))
                .GetGenericArguments().Single();

            var proposedHandlerType = typeof(IQueryHandler<,>).MakeGenericType(queryType, resultType);
            var matchingHandler = allHandlerTypes.FirstOrDefault(t => t == proposedHandlerType);

            if (matchingHandler == null)
            {
                missingHandlers.Add(queryType);
            }
        }

        // Assert
        var missingNames = missingHandlers.Select(t => t.Name).ToList();
        var separator = String.Format("{0}{0}---------------{0}", Environment.NewLine);
        var finalMessage = separator + String.Join(separator, missingNames);
        Assert.IsEmpty(missingHandlers, finalMessage);
    }
}

This goes through your types and determines if you have all required handlers. Another way you can do the same test – to get container to resolve query handlers for all your queries. This is a bit more integration tests and probably will require database set up and accessed from your tests.

Here is the integration tests for the query handlers:

    [Test]
    public void Autoafac_CanResolve_AllQueryHandlers()
    {
        //Arrange
        var allQueryTypes = Assembly.GetAssembly(typeof(IQuery<>)).GetTypes()
                .Where(t => t.IsClass && t.IsClosedTypeOf(typeof(IQuery<>)))
                .ToList();

        // create your container
        var container = AutofacConfig.Configure();

        var errors = new List<String>();

        // Act
        foreach (var queryType in allQueryTypes)
        {
            var resultType = queryType.GetInterfaces()
                .Single(i => i.IsClosedTypeOf(typeof(IQuery<>)))
                .GetGenericArguments().Single();

            var handlerType = typeof(IQueryHandler<,>).MakeGenericType(queryType, resultType);
            try
            {
                container.Resolve(handlerType);
            }
            catch (Exception exception)
            {
                var resolutionException = exception as DependencyResolutionException;
                if (resolutionException != null)
                {
                    errors.Add(resolutionException.Message);
                }
                else
                {
                    errors.Add(exception.ToString());
                }
            }
        }

        // Assert
        var separator = String.Format("{0}{0}--------------{0}", Environment.NewLine);
        var finalMessage = separator + String.Join(separator, errors);
        Assert.IsEmpty(errors, finalMessage);
    }
  • zhuravl

    Hi Max,

    Noted that you have used mixed camelCase and underscode_case for naming methods in your tests. To be honest I used that style before as well. But later came up to using underscore style only (in tests only). Justification is… readability. As a developer I want my tests to be readable, and I can sacrifice existing naming conventions here. It works pretty well for me now.

    Not sure if you’ll be happy with that, but who knows, maybe you’ll find it useful :)

    Thanks!

    • This naming convention for tests come from Roy Osherove: http://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html

      To be honest, the more I use this convention, the less I find it universally acceptable. But for now I have not found other convention that will be expressive and widely acceptable for test names.

      • zhuravl

        I had exactly the same thoughts. I finally realized that I paid too much attention to that. Tests should be readable. I just wanted my team to understand what do these descriptions mean. So now I just use something like

        public void autofac_should_resolve_all_query_handlers()

        or

        public void all_queries_should_always_have_handlers()

        I use “Should” assertion framework, so it perfectly combines with the word “should” I usually use in my test method names.

        Quite easy to read!

        • Since this article, I have started using FluentAssertions which is very similar to Should you talk about. And yes, my team loves it.