TL;DR
This extension will allow any object to invoke a private methodRunPrivateMethod()
.
public static class TestHelpers
{
public static object RunPrivateMethod(this object obj, string methodName, params object[] args)
{
var method = obj
.GetType()
.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
{
throw new ArgumentException(
$"{obj.GetType()} does not contain the method {methodName}",
"methodName"
);
}
return method.Invoke(obj, args);
}
}
var res1 = obj.RunPrivateMethod("SecretInternalMethod");
var res2 = obj.RunPrivateMethod("SecretInternalMethodWithArgs", arg1, arg2);
Explanation
The magic happens mainly withBindingFlags.NonPublic | BindingFlags.Instance
which allows us to use reflection to get the MethodInfo
for the specified private method.
Don't forget to include using statemnets
using System;
and using System.Reflection;
Usage
The following usage example shows how this could be used in a unit testpublic class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
private string GetFullName() // <-- Private Method
{
return $"{FirstName} {LastName}";
}
private string GetFullNameWithNickname(string nickname) // <-- Private Method with argument
{
return $"{FirstName} '{nickname}' {LastName}";
}
}
[Fact]
public void GetFullName__Should_Return_ExpectedResult()
{
// ARRANGE
var test = new Person { FirstName = "Ace", LastName = "Rimmer" };
// ACT
var name = test.RunPrivateMethod("GetFullName"); // <-- without args
var nickname = test.RunPrivateMethod("GetFullNameWithNickname", "what a guy!"); // <-- with args
// ASSERT
name.Should().Be("Ace Rimmer");
nickname.Should().Be("Ace 'what a guy!' Rimmer");
}