There are various ways to test a Class member which is not public
:
- By making the
private
members public
of a class under test
- Breaks the encapsulation principle
- API is modified just for the sake of testing
- By making the
private
members internal
of a class under test and annotate the assembly with internalsVisibleTo
attribute and you can read more about it here
- Breaks the encapsulation principle
- API is modified just for the sake of testing
- Make the
private
members reachable through a public
member of a class under test and test these public
members
- Breaks the encapsulation principle
- API is modified just for the sake of testing
- Use reflection to invoke the non
public
members of a class under test
Using reflection is abstracted in Visual Studio, so we can use:
PrivateObject
to access non public
Instance members of a class under test PrivateType
to access static
members of a class under test
These classes are inside Microsoft.VisualStudio.TestTools.UnitTesting
namespace. I have created code snippets in Visual Studio 2010.
PrivateObject
PrivateObject
class is used to access instance based members of a class under test. The methods and properties of this class are displayed below:
E.g. We have a BankAccount
class that contains a private
method, i.e., VerifyAmount
as displayed below:
public class BankAccount
{
private bool VerifyAmount(double amount)
{
return (amount <= 1000);
}
}
In order to unit test VerifyAmount
method using PrivateObject
class, the code is displayed below:
[TestMethod()]
public void VerifyAmountTest()
{
PrivateObject privateHelperObject = new PrivateObject(typeof(BankAccount));
double amount = 500F;
bool expected = true;
bool actual;
actual = (bool)privateHelperObject.Invoke("VerifyAmount", amount);
Assert.AreEqual(expected, actual);
}
PrivateType
PrivateType
class is used to access the static
non public
members of a class under test. The methods and properties of this class are displayed below:
E.g. We have a BankAccount
class that contains a private static
method i.e., VerifyAmount
as displayed below:
public class BankAccount
{
private static bool VerifyAmount(double amount)
{
return (amount <= 2000);
}
};
In order to unit test VerifyAmount
method using PrivateType
class, the code is displayed below:
[TestMethod()]
public void VerifyAmountTest()
{
PrivateType privateHelperType = new PrivateType(typeof(BankAccount));
double amount = 1000F;
bool expected = true;
bool actual;
actual = (bool)privateHelperType.InvokeStatic("VerifyAmount", amount);
Assert.AreEqual(expected, actual);
}
In both the cases displayed above, i.e., PrivateObject
and PrivateType
, the method names are hardcoded. In order to avoid hard coding, Visual Studio provides an option to create private accessor as displayed below where PrivateBanking
is the name of the project.
Private Accessor automatically gets created when creating unit tests as displayed below:
In the test project, under Test References, you can now see
PrivateBanking.accessor
as displayed below:
The unit tests using the private
accessor for class BankAccount
as displayed below where BankAccount_Accessor
is the class publicises the BankAccount
class and it derives from BaseShadow
class.
[TestMethod()]
[DeploymentItem("PrivateBanking.dll")]
public void VerifyAmountTest1()
{
BankAccount_Accessor target = new BankAccount_Accessor();
int amount = 10;
bool expected = true;
bool actual;
actual = target.VerifyAmount(amount);
Assert.AreEqual(expected, actual);
}
[TestMethod()]
[DeploymentItem("PrivateBanking.dll")]
public void VerifyAmountTest()
{
double amount = 10F;
bool expected = true;
bool actual;
actual = BankAccount_Accessor.VerifyAmount(amount);
Assert.AreEqual(expected, actual);
}
As we are using the accessor now, no hard coding is required for method names as displayed in the code snippet above. The BankAccount_Accessor
class is displayed below:
The BaseShadow
class is used by the publicize
method to help test private
types and is displayed below:
This concludes the article on how to unit test non public
members using Visual Studio 2010.
CodeProject