Until the release of Visual Studio 2012 (VS2012), it was possible to create an accessor class in MS Test code that allowed you to test private and protected methods in classes. In VS2012 this has been deprecated (although not yet removed).
While looking for alternatives for testing private I came across this StackOverflow article about nUnit, and the accepted answer is that the theory is you should only be testing the public methods on a class.
Wrong, wrong, wrong
I contend this is a totally misguided theory. The purpose of unit testing is to ensure our code operates in the way it was intended to operate. If we ignore private code inside the class, we are making an assumption that the public methods will operate in a way that allows us to deterministically test the internal code. This is not necessarily the case, and might even lead to having to change the code to allow us to test the private methods in this way. This would be wrong.
I can see why this theory arises: if a method is private, it’s internal and we the developer did not intend that a production application using that class should use this method. That’s fine: but in unit testing we are not in a production environment, we are in the abstract, testing environment. We are not just ensuring the public methods work, we want to be assured the private ones work as well.
In this case we need to ensure that each method (whether private or public) operates as intended. It cannot be called unit testing if we only test the public class. This is integration testing.
I was debugging an open source library called MvcRouteUnitTesting. This has a private ValueCompare() method that takes two objects and tries to see if they are equal.
There are several edge cases where I suspected this method has a bug, and states that two identical values are not equal, when in fact they are.
If we follow the Public-Only-Theory we would need to create instances of the containing class and set the data such that the method would be called for each test case.
But we are then hostage to the public method implementation: in reality our test is testing both the containing class as well as the method in question. A later revision of the public method code might make our tests pass even though we are trying to test something else.
We are not actually testing just the unit method in question we are testing the whole codebase.