Before we start to see, how a private method can be unit tested using the MS Test? Let us discuss whether it is a good idea to test a private method or not? Often I have seen there are two school of thoughts,
1. Private methods should be tested.
2. Private methods should not be tested.
To put these things in perspective, let us consider a system under test (SUT) Salary class as shown in the listing below.
namespace Calculator
{
publicclassSalary
{
publicint CalculateSal(int bs, int nwd)
{
int ts ;
if(isValidNwd(nwd))
{
ts= bs*nwd;
}
else
{
ts = 1000;
}
return ts;
}
privatebool isValidNwd(int nwd)
{
if (nwd > 8)
{
returntrue;
}
else
{
returnfalse;
}
}
}
}
A system under test Salary class has two functions:
1. The CalculateSal method is a public method and it takes two parameters to calculate the salary
2. The isValidwd method is a private method and it takes one parameter. This function returns true if the number of working days are more than 8, or else it returns false.
3. The CalculateSal method first checks whether the number of working days is valid or not using the private method isValidWd.
4. If the number of working days is valid, then salary is calculated by the multiplication of basic salary and the number of working days, or else it is fixed at $1000.
Now we have a system under test Salary class with two functions.
One opinion is that the private method should not be unit tested separately. This is because the private method is used inside the public method and when we test the behavior of the public method, the behavior of the private method also gets tested.
Another opinion is that the private method must be unit tested for its own behavior in isolation with the other public or private methods. Before we go ahead and see how to test a private method, let us give some thought on whether there is another possible way to work around this.
Violating Single Responsibility Principle
Currently, the system under test Salary class is violating the Single Responsibility Principle because it has two responsibilities:
1. To calculate the salary (public method)
2. To validate the number of working days (private method)
We can’t be sure of good code coverage of SUT Salary class unless we test the validate working days behavior of the class, and is private by design. A good option could be this: while creating the Salary class, we can spilt the responsibilities in two separate classes with public methods to calculate the salary and validate working days. We can then write unit tests for public methods of both classes. Let’s see how to do that:
Writing Unit Test for Private methods
If you’re of the opinion that a private method in the SUT class should be tested, then you have two options:
1. Use Refactoring – but this is bit complex;
2. Use VSTS PrivateObject class - this is simple!
Let’s see how we can use a PrivateObject class to unit test a private method. To use a private object class you need to:
1. Add a reference of Microsoft.VisualStudio.QualityTools.UnitTestFramework in the test project. If you have created project by selecting unit test project templet then this reference would be added by default in the project.
2. Add a namespace Microsoft.VisualStudio.TestTools.UnitTesting.
The constructor of PrivateObjectClass takes the type as the parameter, so here you’ll need to pass type of the SUT Salary class and then on the object of PrivateObjectClass call the invoke method to invoke the private method.
We can test the private method isValidNwd as shown in the listing below:
[TestMethod]
publicvoid ReturnTrueForValidWorkingDays()
{
PrivateObject objToTestPrivateMethod = newPrivateObject(typeof(Salary));
bool result = Convert.ToBoolean(objToTestPrivateMethod.Invoke("isValidNwd", 6));
Assert.AreEqual(result, true);
}
Essentially, we are performing the following tasks:
· Creating an object of PrivateObject class
· Passing a type of Salary class as an input parameter in the constructor
· Using the invoke method to execute the private method of the SUT Salary class
· Passing two parameters in the invoke method: the first parameter is the name of the private method and the second parameter is the argument which will be passed to the private method while executing
And that’s how we can unit test a private method!
Conclusion
In this post we learnt about:
· Whether to test a private method or not
· How to test the private method using the PrivateObject class
I hope this post is useful for you - thanks for reading. Happy coding!