Home-made Private Accessor for Visual Studio 2012+

Why Home-made?

Short answer: Starting with Visual Studio 2012, private accessors cannot be created any more by the IDE.

It seems that this does not bother too many people. The ‘Bring Back Private Accessor’ suggestion on UserVoice has not found any supporters right now.

Nevertheless, I still need access to private members of classes for testing purposes. And I do not want to declare them as internal because these members should not be (mis)used from within the same assembly.

Update 2013-11-09

Axel Mayer noted in the MSDN forums post How to create private accessors in VS 2012 that one can use the command line tool publicize.exe to create private accessors too. See Use Publicize.exe to Create Private Accessors for Visual Studio 2012+ for a detailed description.

The Goals

Just a few things:

  • Type safety
  • Protect from typos
  • Easy to handle when rename is required
  • Encapsulate / hide the use of PrivateObject

Use of PrivateObject

Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject is the base class to build up our own private accessor infrastructure. Well, infrastructure is such a big word. As you will see later, this infrastructure is really lightweight.

The direct use of PrivateObject has some disadvantages. You always have to use strings as parameters to invoke a method or get / set the value of a property. So there is a good chance the call of a method fails because I mistyped the method name. Some casting issues come up too. And using async / await in .NET 4.5, the direct use of PrivateObject.Invoke does not look really funny.

The direct use of PrivateObject looks like this

// Create an instance of the class to be tested.
ClassToBeTested instance = new ClassToBeTested ();

// Create a PrivateObject to access private methods of instance.
PrivateObject privateObject = new PrivateObject(instance);

// Create parameter values
object[] args = new object[] { "SomeValue" };

// Call the method to be tested via reflection, 
// and pass the parameter, and cast the result
int result = (int) privateObject.Invoke("PrivateMethod", args);

// Do some validation stuff

Create an Accessor Class

The first step to get away from this unpleasant and code inflating use of PrivateObject is to create an accessor class inside the unit test assembly.

This accessor class will hide the usage of PrivateObject. It gives type safety and helps to avoid typos on method- and property names. In case a member of the tested class is renamed, there is one single place to change in the test assembly. All other changes in the unit test can be done by Visual Studio renaming support.

A short version of the accessor to ClassToBeTested might look like this:

internal ClassToBeTestedAccessor
{
  private PrivateObject PrivateObject { get; set; }

  internal ClassToBeTestedAccessor()
  {
    PrivateObject = new PrivateObject(new ClassToBeTested());
  }

  internal int PrivateMethod
    (
    string parameter
    )
  {
    return ((int) PrivateObject
      .Invoke("PrivateMethod", new object[] { parameter }));
  }
}

And the test method using the accessor changes to this:

// Create an instance of the accessor.
ClassToBeTestedAccessor accessor = new ClassToBeTestedAccessor ();

// Call the method to be tested
int result = accessor.PrivateMethod("SomeValue");

// Do some validation stuff

Now the test method itself already looks the way I like it.

Make Accessor Reusable

Let’s assume there is the need for more than one accessor class in the test assembly. Then it might make sense to put some functionality into a base class for reuse purposes.

The base class should keep the instance of the tested class and the PrivateObject to access it. This means it have to be generic to get a type safe implementation.

This will be the starting point:

internal abstract class PrivateAccessorBase<T>
{
  private PrivateObject PrivateObject { get; set; }

  public T TestInstance 
    { get { return ((T)PrivateObject.Target); } }

  internal PrivateAccessorBase
      (
      T instance
      )
    {
      PrivateObject = new PrivateObject(instance);
    }
}

Please notice the public property TestInstance. This proporty gives access to the instance that is encapsulated by the private accessor. In case the unit test method needs to access public members of the tested class too, use this proporty.

What is common in my unit tests is to get or set the value of a property and to call a method. Therefore, the base class should offer the ability to do that.

Property Access

To get a property value, one might implement a method like this:

protected TReturnValue GetPropertyValue<TReturnValue>
  (
    string propertyName
  )
{
  return ((TReturnValue)PrivateObject
    .GetProperty(propertyName, null));
}

But this implementation still requires to pass the name of the property as a string. This can be avoided by using the call stack (in case you are using .NET 4.5 or higher, please have a look below to avoid StackFrame usage):

protected TReturnValue GetPropertyValue<TReturnValue>()
{
  // Need to remove the "get_" prefix from the caller's name
  string propertyName 
    = new StackFrame(1, true).GetMethod().Name
      .Replace("get_", String.Empty);

  return ((TReturnValue)PrivateObject
    .GetProperty(propertyName, null));
}

Setting a property value looks quite similar:

protected void SetPropertyValue
  (
  object value
  )
{
  // Need to remove the "set_" prefix from the caller's name
  string propertyName 
    = new StackFrame(1, true).GetMethod().Name
      .Replace("set_", String.Empty);

  PrivateObject.SetProperty(propertyName, value, new object[] { });
}

Having this base class, we can implement the ClassToBeTestedAccessor like this:

internal ClassToBeTestedAccessor
  : PrivateAccessorBase<ClassToBeTested>
{
  internal ClassToBeTestedAccessor ()
    : base(new ClassToBeTested())
  {
  }

  internal int PrivateProperty
  {
    get { return (GetPropertyValue<int>()); }
    set { SetPropertyValue(value); }
  }
}

The usage of the property by the test class does not differ from the usage of ‘normal’ properties:

// Create an instance of the accessor.
ClassToBeTestedAccessor accessor = new ClassToBeTestedAccessor ();

// Set the value
accessor.PrivateProperty = 231;

Debug.WriteLine("PrivateProperty: >{0}<", accessor.PrivateProperty); 

Method Access

Based on this, it is simple to implement the access of non-public methods in the accessor base class.

// Implemented by PrivateAccessorBase
protected TReturnValue Invoke<TReturnValue>
  (
   params object[] parameter
  )
{
  return ((TReturnValue)PrivateObject.Invoke(
    new StackFrame(1, true).GetMethod().Name, parameter));
}

The accessor class uses this method like this:

// Usage by ClassToBeTestedAccessor
internal int PrivateMethod
  (
  string parameter
  )
{
  return (Invoke(parameter));
}

Using the PrivateAccessorBase together with a derived accessor class, the typo danger is eliminated. We got type safety, the accessor implementation does not contain PrivateObject usage, and there is a single place to be changed when some property or method names of the tested class will change.

Preconditions

There is only one precondition: The properties and methods names of the accessor class have to match 100 percent with the corresponding members of the tested class!

Avoid Inlining

One thing really important when using the StackFrame is to make sure the caller's name will not change. How might this happen? When the JIT compiler thinks it should optimize the code by inlining methods.

This would be fatal when using the call stack to get the name of the original caller. As soon as a method is inlined, the call stack changes.

Sample: Assume ClassToBeTestedAccessor.PrivateMethod will be optimized, because it only contains the call to PrivateAccessorBase.Invoke. In this case, the name of the caller in PrivateAccessorBase.Invoke won't be 'PrivateMethod' any more, but the name of the method that called ClassToBeTestedAccessor.PrivateMethod. Using this name, let's assume it is 'TestPrivateMethod', as the method name parameter of PrivateObject.Invoke, the test will fail with an exception, telling the method 'TestPrivateMethod' was not found.

Even if unit tests normally run in debug mode (the 'Optimize code' option is not set in the project's build configuration), one should be aware of this. To make sure the JIT compiler does not inline a method, set the [MethodImpl(MethodImplOptions.NoInlining)] attribute. The sample solution shows how and where.

Changes in .NET 4.5

In case you can use .NET 4.5 or above, you don't have to care about inline optimization 🙂

.NET 4.5 introduced the class CallerMemberNameAttribute. Using this class, there is no need to worry about these things. The attribute is processed by the C# compiler when it produces the IL code. Optimization is done by the JIT compiler later on (see forum post CallerMemberNameAttribute and Inlining).

For the .NET 4.5 implementation, the usage of MethodImpl and StackFrame is obsolete. The PrivateAccessorBase changes to this:

// Implemented by PrivateAccessorBase
protected TReturnValue GetPropertyValue<TReturnValue>
  (
  [CallerMemberName] string callerName = null
  )
{
  return ((TReturnValue)PrivateObject.GetProperty(callerName, null));
}

protected void SetPropertyValue
  (
  object value,
  [CallerMemberName] string callerName = null
  )
{
  PrivateObject.SetProperty(callerName, value, new object[] { });
}

protected TReturnValue Invoke<TReturnValue>
  (
  [CallerMemberName] string callerName = null,
  params object[] parameter
  )
{
  return ((TReturnValue)PrivateObject.Invoke(callerName, parameter));
}

Please notice that even the removal of the 'get_' / 'set_' prefix is not required any more.

The ClassToBeTestedAccessor has to name the parameter passed to PrivateAccessorBase.Invoke to make sure the first parameter is not interpreted as the caller method name.

// Implemented by ClassToBeTestedAccessor
internal string ProtectedMethod
  (
  string parameterValue
  )
{
  // Need to name the parameter, 
  // otherwise the first parameter will be 
  // interpreted as caller's name.
  return (Invoke(parameter: parameterValue));
}

Test Static Member

To access static class members, no class instance or PrivateObject is required. The PrivateAccessorBase collects all properties and methods the type defines, using the static constrcutor.

// Implemented by PrivateAccessorBase
private static IEnumerable DeclaredProperties { get; set; }

private static IEnumerable DeclaredMethods { get; set; }
…
static PrivateAccessorBase()
{
  TypeInfo typeInfo = typeof(T).GetTypeInfo();

  PrivateAccessorBase<T>.DeclaredProperties 
    = typeInfo.DeclaredProperties;

  PrivateAccessorBase<T>.DeclaredMethods 
    = typeInfo.DeclaredMethods;
}

One have to search for the property / method having the matching name, and invoke it.

// Implemented by PrivateAccessorBase
protected static TReturnValue GetStaticPropertyValue<TReturnValue>
  (
  [CallerMemberName] string callerName = null
  )
{
  return ((TReturnValue)PrivateAccessorBase<T>
    .DeclaredProperties
      .Single(info => info.Name.Equals(callerName))
        .GetValue(null));
}

protected static void SetStaticPropertyValue
  (
  object value,
  [CallerMemberName] string callerName = null
  )
{
  PrivateAccessorBase<T>.DeclaredProperties
    .Single(info => info.Name.Equals(callerName))
      .SetValue(null, value);
}

protected static void InvokeStatic
  (
  [CallerMemberName] string callerName = null,
  params object[] parameter
  )
{
  PrivateAccessorBase<T>.DeclaredMethods
    .Single(info => info.Name.Equals(callerName))
      .Invoke(null, parameter);
}

Please note that this is the .NET 4.5 implementation. For .NET version < 4.5, please refer to the sample solution.

Test Async Methods

Having the above in place, and putting it together with the description of the post Unit-Testing of Private Async Methods with Visual Studio, it is easy to extend the base class to be ready for calling async methods.

// Implemented by PrivateAccessorBase
protected async Task<TReturnValue> InvokeAsync<TReturnValue>
  (
  [CallerMemberName] string callerName = null,
  params object[] parameter
  )
{
  TReturnValue returnValue 
    = await (Task<TReturnValue>)PrivateObject
      .Invoke(callerName, parameter);

  return (returnValue);
}

The derived class uses it like this:

// Implemented by ClassToBeTestedAccessor
internal async Task<double> PrivateMethodWithReturnValueAsync
  (
  int millisecondsDelay,
  string outputText
  )
{
  double returnValue 
    = await InvokeAsync<double>
      (parameter: new object[] { millisecondsDelay, outputText });

  return (returnValue);
}

And the testing class uses the accessor this way:

// Implemented by ClassToBeTestedTest
[TestMethod]
public async Task TestPrivateMethodWithReturnValueAsync()
{
  int millisecondsDelay = 300;
  string testValue = "method unit test";

  ClassToBeTestedAccessor accessor 
    = new ClassToBeTestedAccessor();

  double result 
    = await accessor
      .PrivateMethodWithReturnValueAsync(millisecondsDelay, testValue);

  // Do validation stuff
}

Not Complete

The intention of this post and the sample solution is to give you an idea on how to create a home-made private accessor, and what to take care of when doing so.

The intention is not to offer a complete substitute of Visual Studio's Private Accessor Creation feature.

Accordingly, not all possible unit test scenarios are covered. Please feel free to extend the code for your needs and share your solutions and ideas with us by adding comments describing it.

Conclusion

Having this accessor base class, the creation of private accessors should be quite easy. Of course, not as easy as clicking a menu item, but better than fiddling around with PrivateObject.

The code snippets in this post might look a little bit complex and / or confusing. In this case, try to focus on the test class and accessor. Forget about the PrivateAccessorBase.

I hope you agree that both the creation of the accessor and the usage by the test class will be very comfortable and straightforward, having PrivateAccessorBase in place.

The Sample Solution

The sample solution contains four projects:

  • ConsoleApplication contains the class to be tested, based on .NET 4.0.
  • ConsoleApplication.4.5 contains the class to be tested, based on .NET 4.5.
  • ConsoleApplication.Test contains the PrivateAccessorBase, the accessor class, and the unit test class for ConsoleApplication, based on .NET 4.0.
  • ConsoleApplication.Test.4.5 contains the PrivateAccessorBase, the accessor class, and the unit test class for ConsoleApplication.4.5, based on .NET 4.5.

The class that is tested is ClassWithNonPublicMembers, located in the ConsoleApplication… projects.

You need Visual Studio 2012 or higher to build the solution.

Here you can download the code.

Test Explorer Output

Links

Upgrading Unit Tests from Visual Studio 2010

'Bring Back Private Accessor' suggestion on UserVoice

Eric Gunnerson's Compendium: Why doesn't C# have an 'inline' keyword?

CallerMemberNameAttribute

Forum question CallerMemberNameAttribute and Inlining

MSDN forum post How to create private accessors in VS 2012

Use Publicize.exe to Create Private Accessors for Visual Studio 2012+