Thursday, September 16, 2010

How to test a class member that is not public using Visual Studio 2010

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 at http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx
    • 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
image
e.g. We have a BankAccount class that contains a private method i.e. VerifyAmount as displayed below
public class BankAccount
{
//Private method to test
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()
{
//Using PrivateObject class
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
image
e.g. We have a BankAccount class that contains a private static method i.e. VerifyAmount as displayed below
public class BankAccount
{
//Private static method under test
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.
image
Private Accessor automatically gets created when creating unit tests as displayed below
image
In the test project under Test References you can now see PrivateBanking.accessor as displayed below
image
The unit tests using the private accesser for class BankAccount as displayed below where BankAccount_Accessor is the class publicizes the BankAccount class and it derives from BaseShadow class.
//To test non public Instance member
[TestMethod()]
[DeploymentItem("PrivateBanking.dll")]
public void VerifyAmountTest1()
{
BankAccount_Accessor target = new BankAccount_Accessor(); // TODO: Initialize to an appropriate value
int amount = 10; // TODO: Initialize to an appropriate value
bool expected = true; // TODO: Initialize to an appropriate value
bool actual;
actual = target.VerifyAmount(amount);
Assert.AreEqual(expected, actual);            
}
 
//To test non public static member
[TestMethod()]
[DeploymentItem("PrivateBanking.dll")]
public void VerifyAmountTest()
{
double amount = 10F; // TODO: Initialize to an appropriate value
bool expected = true; // TODO: Initialize to an appropriate value
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 code snippet above. The BankAccount_Accessor class is displayed below
image
The BaseShadow class is used by the publicize method to help test private types and is displayed below
image
This concludes the article on how to unit test non public members using Visual Studio 2010.

No comments:

Post a Comment