Description
Given there is the need to unit-test a private async
method. The class to be tested might look like this:
public ClassWithPrivateAsyncMethod { // Some stuff private async Task PrivateMethodAsync ( string input ) { // Call some async framework method var result = await SomeFrameworkMethodAsync(input); // do something with the result } // Some more stuff }
In former – pre VS 2012 – times, one would have right-clicked inside this method, selected “Create Private Accessor…” and “Create Unit Tests…”, and implemented the test. Well, this was then, and this is now. Nowadays, Visual Studio does not have the ability to create private accessors and unit test bodies.
But still, you are able to create a unit test yourself. And instead of having a private accessor, we can use Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject
, which is included in %Program Files (x86)%\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v4.0\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll (path might vary slightly with version changes, this is the path for Visual Studio 2012). To use this assembly, I had to set the Copy Local property of the reference to true.
Instead of wring much more prose, here is the implementation of the unit test method:
using Mut = Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; // some other usings [TestClass] public ClassWithPrivateAsyncMethodTest { [TestMethod] public async Task TestPrivateMethodAsync() { // Create an instance of the class to be tested. ClassWithPrivateAsyncMethod instance = new ClassWithPrivateAsyncMethod(); // Create a PrivateObject to access private methods of instance. Mut.PrivateObject privateObject = new Mut.PrivateObject(instance); // Create parameter values object[] args = new object[] { "SomeValue" }; // Call the method to be tested via reflection, // pass the parameter, and await the return await (Task)privateObject.Invoke("PrivateMethodAsync", args); // Do some validation stuff } // Some more stuff }
Have a look at the checklist to be sure not to miss a detail.
Checklist
Combine async
with return type Task
in method declaration. Even if the method returns void
, the declaration should be async Task
. Otherwise, it cannot be awaited, what would lead to some trouble in testing the method.
Add reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll in your test project. You have to browse for it. The assembly can be found in %Program Files (x86)%\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v4.0\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll (path might vary slightly with version changes, this is the path for Visual Studio 2012).
Set Copy Local to true for the Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll reference.
Declare an alias for the Microsoft.VisualStudio.TestTools.UnitTesting
namespace if you also use Microsoft.VisualStudio.TestPlatform.UnitTestFramework
. This helps you to avoid using classes of the wrong namespace. There are some overlappings.
Declare testing method async Task
, not async void
. Otherwise, it will not be recognized as a test method, even when the TestMethodAttribute
is set.
Use PrivateObject
to access private methods of instances. It is located in the namespace Microsoft.VisualStudio.TestTools.UnitTesting
.
Cast PrivateObject.Invoke
‘s return value to Task
to make sure the call can be awaited.
Await PrivateObject.Invoke
. Otherwise, the tests in the testing method might be performed before the tested method returns.