Originally posted on: http://geekswithblogs.net/abhi/archive/2013/11/20/unittesting-non-public-methods.aspx
Before we proceed any further, I should say this, Testing through this public API should be your first choice.Alternative for
Abstract Base Classes
One common case is when an abstract base class definesfunctionality in some protected methods, and there
are a series of inheriting classes using those methods without overriding them. In this case, rather than
choosing one inheriting member at random to test the methods, you can simply create a “Fake” class locally in
your test project that inherits from the base class. This “Fake” could then
expose the protected members in some public members of its own; and your tests
would run against the “Fake” class.
The following is a simplified example of how to create a
“Fake” object for this purpose:
publicabstractclassMyBaseClass<T>
{
protectedstring MyProtectedMethod()
{
returntypeof(T).ToString();
}
}
…
internalclassFakeClass : MyBaseClass<Int32>
{
publicstring
CallMyProtectedMember()
{
returnbase.MyProtectedMethod();
}
}
…
[TestMethod]
publicvoid TestMyProtectedMember()
{
FakeClass
fake = newFakeClass();
string retVal
= fake.CallMyProtectedMember();
Assert.AreEqual(retVal,"System.Int32");
}
Alternative using
PrivateObject
When necessary, the PrivateObject class can be used to expose non-public members to your unit tests. The class uses reflection to access the members based on a string identifier. The following is an example of how to test the private method above using PrivateObject.
Note: the example is NOT a case where PrivateObject should be used, instead this is meant to show the simplest usage for the PrivateObject class.
[TestMethod()]
publicvoid GetStringArgIsOneTest()
{
//Arrange
var myClass = newMyClass();
var privObj = newPrivateObject(myClass);
//Act
object retVal
= privObj.Invoke("GetString", new []{typeof(Int32)}, newobject[]{1});
//Assert
Assert.AreEqual(retVal.ToString(),"Hello World");
}
Unit
Testing Private Static Methods
You cannot access static methods with the PrivateObject class.
Instead of the PrivateObject class, you should use the PrivateType class. You
can think of PrivateObject as being an object, containing only instance methods
while PrivateType is a type which is how you would call static methods.
Example:
PrivateType privateType = newPrivateType(typeof(SomeClass));
var actual = privateType.InvokeStatic("SomeStaticMethod", 1);
actual.Should().Be(expected);