Failure is inevitable


Verifying NHibernate Entities Contain Only Virtual Members

One requirement that NHibernate imposes on your object model is that all public members must be virtual in order to support lazy loading.  I got really tired of getting a yellow-screen-of-death while working on Fail Tracker every time I added a new member to my domain and forgot to mark it as virtual.  So, I added a simple test to enforce the convention.

Here’s the error I was getting just about every single time I added a new property or method to my entities:


Annoying.  I prefer to catch things at compile time when possible, and at test-time otherwise.  I hate it when I catch something only at runtime.  Fortunately a little bit of reflection is all that’s needed to enforce a “all public methods and properties on entities must be virtual” convention:

public void all_domain_entities_should_contain_only_virtual_members()
    var types = from t in typeof (Project).Assembly.GetTypes()
                where t.Namespace == typeof (Project).Namespace &&
                      t.IsPublic &&
                      !t.IsAbstract &&
                select t;

    var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;

    var nonVirtualMembers = (from t in types
                             from m in t.GetMethods(bindingFlags)
                             where !m.IsVirtual
                             select t.Name + "." + m.Name).Union(
                                 from t in types
                                from p in t.GetProperties(bindingFlags)
                                 where !p.GetGetMethod(true).IsVirtual
                                 select t.Name + "." + p.Name);

    if (nonVirtualMembers.Any())
        Assert.Fail("Non-virtual members found in domain type: \r\n" + string.Join("\r\n", nonVirtualMembers.ToArray()));

Now when I add a new method or property to one of my entities, I’ll get a failing test when I inevitably forgot the ‘virtual’ keyword.  Yes, I should have some integration tests that catch this sort of thing as well, but I actually like this approach as it’s very specific about the convention its enforcing. 

About Matt Honeycutt...

Matt Honeycutt is a software architect specializing in ASP.NET web applications, particularly ASP.NET MVC. He has over a decade of experience in building (and testing!) web applications. He’s an avid practitioner of Test-Driven Development, creating both the SpecsFor and SpecsFor.Mvc frameworks.

He's also an author for Pluralsight, where he publishes courses on everything from web applications to testing!

blog comments powered by Disqus