Test for default constructors in models for Entity Framework

Entity Framework relies on models to have a default constructor with no parameters. But if you are working with DDD often you would like to have some parameters in your constructors. And then slam a protected default constructor just for EF not to throw exceptions.

So you end up with code like this:

public class Product
{
    protected Product()
    {
        // This is required for EF
    }

    public Product(String name)
    {
        Name = name;
    }

    public String Name { get; set; }
}

The first constructor must not be used by developers, so you make it protected – this is good enough for EF.

If you are using Resharper, it highlights unused code. And that constructor will be highlighted. And some clever OCD-developer will look into that class one day, see the unused code and delete it (presume there is no comment there). And what will happen? Some time later, some poor customer will open a page with list of Products and see an exception message (worst case scenario).

To mitigate the problem with missing default constructor here is my test:

[Test]
public void AllDomainModels_Always_HaveDefaultEmptyConstructor()
{
    var errors = new List<String>();
    var types = GetModelsTypes();

    foreach (var type in types)
    {
        const BindingFlags BindingFlags = BindingFlags.Public 
                | BindingFlags.NonPublic | BindingFlags.Instance;

        // get all public and non-public constructors with no parameters
        var constructor = type.GetConstructor(BindingFlags, null, Type.EmptyTypes, null);

        if (constructor == null)
        {
            var message = String.Format("Model {0} does not have a default constructor. Add [NotMapped] if class is not used by EF", type);
            errors.Add(message);
        }
    }

    var finalMessage = String.Join(Environment.NewLine, errors);
    Assert.IsEmpty(errors, finalMessage);
}


public static IEnumerable<Type> GetModelsTypes()
{
    // need to reference one of your domain models here
    var allTypes = Assembly.GetAssembly(typeof(Product)) 
        .GetTypes()
        .ToList();

    // I'm presuming your domain models will be in one namespace
    var modelsTypes = allTypes.Where(t => t.Namespace != null 
                      && t.Namespace.StartsWith("MyProject.Domain.Models"))
        .Where(t => t.IsClass)
        .Where(t => t.IsPublic)
        .Where(t => !t.IsAbstract)
        .Where(t => !t.IsNested)
        // ignoring the classes that are marked with [NotMapped]
        .Where(t => !t.GetCustomAttributes()
            .Select(a => a.GetType()).Contains(typeof(NotMappedAttribute)))
        .OrderBy(t => t.Name)
        .ToList();

    return modelsTypes;
}

So next time somebody forgets the default constructor on a model, this will be highlighted by a failing test. Awesomes!