Calling private members in unit tests without specifying the name as a string

In my previous post  I mentioned the PrivateObject class to call private fields or properties in unit tests. PrivateObject expects a string to specify the name of the private member.
What bothers me about this approach is that you have to change all the usages of the string if you rename the private property. I hate to put these strings in my code and lose all the compile time advantages, so I went for a different approach.

First of all I created a static generic NameOf class with a method named Member, which accepts a lambda expression pointing to a field or property and returns the name of the field or property.

public static class NameOf<T>
{
    public static string Member(Expression<Func<T, object>> expression)
    {
        var memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
        {
            var unaryExpression = expression.Body as UnaryExpression;
            if (unaryExpression == null)
                throw new ArgumentException("memberExpression");

            memberExpression = unaryExpression.Operand as MemberExpression;
            if(memberExpression == null)
                throw new ArgumentException("memberExpression");
        }

        return memberExpression.Member.Name;
    }
}

This already solves the need to use strings when getting the name of a public property with a private setter. The UnaryExpression is used for boolean members, in which the operand delivers us the eventual MemberExpression. Suppose there is an Employee class with a public Property IsActive, but a private setter, then we can fetch the name of the IsActive property like this:

var name = NameOf<Employee>.Member(x => x.IsActive);

But how can we use the NameOf class for private properties or fields? It is only possible to access the properties directly when we use them inside the class, so the only way to expose their names is to declare them inside the class. Suppose the Employee class has a private field lastName, then the name can be exposed like this:

public static readonly string lastNameFieldName = NameOf<Employee>.Member(x => x.lastName);

This is a very invasive way to expose private member names and it doesn’t make your classes look very neat. Let’s clean that up a little.

First of all, the name field can be made internal, so other assemblies can not access it. To use the lastNameFieldName in a Unit Test project I made the internals visible to it by using the InternalVisibleToAttribute in the AssemblyInfo file of the assembly of the Employee class:

[assembly: InternalsVisibleTo("--Your Unit Test assembly--")]

Secondly I wanted to move the private field names to a separate file, the only way to do this (correct me if I’m wrong) is to make use of partial classes. I have made the following directory structure:

UnitTestHelp - Microsoft Visual Studio (Administrator)_2012-05-24_07-29-23

Finally, I declared an internal static class to expose these fields, so the final implementation of my private member partial class for Employee looks like this:

public partial class Employee
{
    internal static class PrivateMemberNames
    {
        internal static readonly string Name = NameOf<Employee>.Member(x => x.Name);
        internal static readonly string lastName = NameOf<Employee>.Member(x => x.lastName);
    }
}

To access the name of the lastName field I can now simply use the following statement:

Employee.PrivateMemberNames.lastName

To make the use of PrivateObject even more simple, I created 2 extension methods on object to get and set private members:

public static T GetMemberValue<T>(this object objectWithMember, string memberName)
{
    PrivateObject privateObject = new PrivateObject(objectWithMember);
    var value = ValidateMemberName<T>(memberName, privateObject);
    return (T)value;
}

public static void SetMemberValue<T>(this object objectWithMember, string memberName, T value)
{
    PrivateObject privateObject = new PrivateObject(objectWithMember);
    ValidateMemberName<T>(memberName, privateObject);
    privateObject.SetFieldOrProperty(memberName, value);
}

Both were made generic, which enables me to work more type safe. The ValidateMemberName method validates if the member your are setting is of the type specified in te generic argument.

To round things up: getting and setting private members on the Employee class now works like this:

employee.SetMemberValue(Employee.PrivateMemberNames.lastName, "Boonen");
var lastName = employee.GetMemberValue<string>(Employee.PrivateMemberNames.lastName);

I find this solution pretty neat, although it is still invasive. You should probably avoid calling private members in unit test code as much as possible. But in a DDD context or when using legacy code you sometimes have no other choice.

I uploaded the source code, together with some basic unit tests to GitHub. Feel free to use it, extend it or comment on it!