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 IEnumerableDeclaredProperties { 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.
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?
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+
Hallo Stefan,
ich habe Deinen Vortrag bei der Dotnet Usergroup Frankfurt gehört.
Bei mir gibt es auch unter VS 2012 das Tool Publicize.exe.
Es ist zwar langsam, erstellt aber schöne Private-Accessor-Klassen.
Nicht getestet habe ich, was mit Async/Await passiert.
Viele GrĂĽĂźe
Axel
Hello Stefan,
A very helpful article, indeed. This really helped me in using tests from within Visual Studio 2013. Now I have an issue that I was not able to solve by myself.
How to access private indexer?
How to access, let say: “protected byte this[int index]” ?
How to extend the PrivateAccessorBase class? I’m stuck.
Regards
Christian,
Here is how I extended the sample code for the .NET 4.5 framework:
Added this to
ClassWithNonPublicMembers
:for a zero-based index, and
for a string-based index.
Then I extended the class
PrivateAccessorBase<T>
of the test project with the following code:Of course, the accessor class
ClassWithNonPublicMembersAccessor
needs to be extended too:and
.
Now only a test is missing in the class
ClassWithNonPublicMemberTest45
(just a driver, no real test):The trace output is:
Hth,
Stefan
Thanks Stefan,
Should try this soon.
As a Newbie, I am continuously searching online for articles that can aid me. Thank you