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:
[Test]
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 &&
t.IsClass
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.
Tags: