Category Archives: Software Architecture

10 Golden Rules for Unit Tests

There are some rules of thumb I encourage my team to follow when writing unit tests and they are as follows:

1. System under test should be clearly defined.  A variable naming convention I have personally adopted is “sut” to stand for “system under test”.

2.  Each test should abide by the AAA principle of Arrange, Act and Assert.  There should be a clear demarcation between these three different aspects of a test.

3.  As part of the Arrange phase, all dependencies of the system under test should be clearly defined, and mocks used where to abstract away external dependencies, whenever possible. Also, always best to mock via interfaces instead of abstract base classes. No container registrations here and no hidden dependency injection into the system under test.

4.  As part of the Arrange phase, all additional dependencies such as file names or configuration items should be explicit and clearly defined. Avoid depending on external entities which will not guarantee consistency in your test results such as webservices, etc.

5.  During the Acting phase, it should be clear which of the APIs of the system under test is being exercised and this method being exercised should typically return a response.

6.  Assertion should be based upon the response of the method acted upon from the previous phase.  Assert the response is what you expect.  Avoid asserting that the method under test was called.  For example, this is a good assertion:

// arrange
var sut = new ResourceController();

// act
var result = sut.GetResource(new Dictionary()).ToList();
// assert
Assert.AreEqual(2, result.Count); 
Assert.AreEqual("Kanata", result[0].AdditionalProperties["placeofservicetypename"]); 

Assuming the same entities defined in the Arrange section above,

resourceCacheMock.Verify(sut => sut.GetResources(new Dictionary().....)

The latter does not guarantee we get the correct results but rather the fact that some other resource was invoked, which means we need to know internally how sut.GetResource works.

8.  Minimize the number of asserts in a test.  I would not say a test should be restricted to one assert as this is an artificial constraint which breaks down too often.  Instead, I would advocate for a minimalist approach, encouraging developers to ensure to think about splitting a test if the number of asserts is greater than 3 for example.

9.  Keep tests small or digestable.  It should be relatively straight forward to look at a test and determine what it is doing.  If a colleague cannot decipher the purpose of a test within a couple of minutes, it is overly complex or doing too much.

10.  Test names should be clearly indicate what the test is trying to accomplish.

Advertisements

The EntityMappingService – Application mapping in a Consistent and Disciplined Manner

Here’s a question for you:

How do you map, in a consistent, loosely couple, testable, and extensible manner, objects from your services domain to objects in your application domain?

I have run across various approaches:

  1. Inline in the code using static methods or copy paste code.
  2. Custom code sprinkled all over as needed.
  3. Dedicated service with a well defined interface dedicated to mapping.

Of all these approaches, I am fond of the last one for the following reasons:

  1. Mapping is cross cutting and should be re-usable.
  2. Mapping is not business logic and should be encapsulated away from where such business logic decisions are made.
  3. Mapping is noisy and pollutes the service or view model logic.
  4. Mapping is a single responsibility which can be tested in isolation. The Mappers and mapping repository can be unit tested!

For example, say you have a concept called in invoice represented in two domain; in the RESTFul service domain and your application domain. Once these objects have been retrieved from the service, you will have to map them to corresponding objects in your application domain. To do this, we define a

public class InvoiceToInvoiceDtoMapper : EntityMapperBase
{
    protected override InvoiceDto DoMap(Invoice source, EntityMappingContext context)
        {
            return new InvoiceDto 
            {
               Number = source.Number,
               AmountDue = source.TotalCharge
               ServiceDate = source.ServiceDate
            };
        }
}

There will be many of such mappings with each mapping strategy encapsulated by a mapper. How do we manage all of these? We use a central repository of mappers, called the EntiyMapperService.

What is so good about the Entity Mapping Service

It’s responsibility is determining which of these mappers from map from one type to another and delegating the mapping to the mapper in question. It’s interface could look like this:

 public interface IEntityMappingService
    {
      
        void RegisterEntityMapper(IEntityMapper mapper);

        void UnRegisterEntityMapper(IEntityMapper mapper);

        bool CanMap();

        TTarget Map(object source, EntityMappingContext mappingContext = null);
    }

A naive implementation of such a service could look like this:

 public sealed class EntityMappingService : IEntityMappingService
    {
        private readonly List _entityMappers = new List();

        public EntityMappingService()
        {
        }       

        public void RegisterEntityMapper(IEntityMapper mapper)
        {
            if (mapper == null)
                throw new ArgumentNullException("mapper");

            _entityMappers.Add(mapper);
        }

        public void RegisterEntityMappers(IEnumerable mappers)
        {
            foreach (var translator in mappers)
                RegisterEntityMapper(translator);
        }

        public void UnRegisterEntityMapper(IEntityMapper mapper)
        {
            if (mapper == null)
                throw new ArgumentNullException(nameof(mapper));

            _entityMappers.Remove(mapper);
        }

        public bool CanMap()
        {
            return CanMap(typeof(TSource), typeof(TTarget));
        }

        public bool CanMap(Type sourceType, Type targetType)
        {
            if (targetType == null)
                throw new ArgumentNullException(nameof(targetType));
            if (sourceType == null)
                throw new ArgumentNullException(nameof(sourceType));
          
            var entityMapper = FindEntityMapper(targetType, sourceType);
            return entityMapper != null;
        }

        public TTarget Map(object source, EntityMappingContext mappingContext = null)
        {
            return (TTarget)Map(typeof(TTarget), source, mappingContext);
        }
     
        public object Map(Type targetType, object source, EntityMappingContext mappingContext)
        {
            if (targetType == null)
                throw new ArgumentNullException("targetType");

            if (source == null)
            {
                return null;
            }

            Type sourceType = source.GetType();
          
            var entityMapper = FindEntityMapper(targetType, sourceType);
            if (entityMapper != null)
            {
                return entityMapper.Map(targetType, source, mappingContext);
            }

            throw new EntityMapperException(string.Format("No mapper is available to perform the operation from {0} to {1}.", sourceType, targetType));
        }

  
        public IEntityMapper FindEntityMapper(object parameter)
        {
            return _entityMappers.FirstOrDefault(t => t.CanMap(parameter));
        }

        public IEntityMapper FindEntityMapper(Type targetType, Type sourceType)
        {
            return _entityMappers.FirstOrDefault(t => t.CanMap(sourceType, targetType));
        }

        public IEntityMapper FindEntityMapper()
        {
            return _entityMappers.FirstOrDefault(t => t.CanMap(null));
        }
    }

Please note that this mapper does not take into consideration multi-threading nor does it prevent registration of duplicates.

What is wrong with the other approaches

 
Software is craft and more like an art and there is not a single correct answer. There are better ways of crafting good code and as I have always advised my developers, write code as if you are writing a story. With this mentality, you will find yourself crafting cleaner, robust and more testable code over and over again.

Happy Coding.