Unit testing the critical methods of your application is important.
Generally, I focus on testing public methods because this is the interface that others use to interact with my library. Testing only public methods also safeguards me from modifying unit tests every time I refactor or optimize the encapsulated code of my libraries.
Unfortunately, sometimes critical methods are marked Private. Because I always create my unit tests in a separate project, this presents a problem: Private methods are only accessible to other methods in the same class; You cannot call a Private method from an external assembly.
You have several options when testing Private methods from a separate project.
- Change the method's accessor to Public
- Create a public 'accessor' to the method
- Use reflection to access the method
- Test a public method that calls this method.
- Change the method's accessor to Internal and make Internal methods visible to your test project.
Each of these approaches has its shortcomings
Change the method's accessor to Public
This is probably too extreme as it breaks any abstraction you were trying to create. Too many public methods can clutter an API, making it overly complex.
Create a public 'accessor' to the method
This involves creating a public class and method decorated with the [Shadowing] attribute. It definitely adds a level of complexity to your class. When you ask MSTest to create a new Unit Test of a private method, you will be prompted to create an accessor.
Test a public method that calls this method
This is a popular choice. The idea is that public methods call private methods, so testing your public methods will call and test your private methods. To get good code coverage, you will need to know which methods are called (an approach known as "White Box testing".) Some people don't like to call this a unit test because multiple methods are called.
Use reflection to access the method
This is the most complicated of the methods listed here; But, if you don't have the source code and you feel you must test a private method, this is your only option.
Change the method's accessor to Internal and make Internal methods visible to your test project.
This method is a good compromise. By default, Internal methods are available only to other methods in the same assembly. However, you can an external project explicit permission to access Internal methods by adding the following line to AssemblyInfo.cs class of the file containing the method you want to test.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("TestProject")]
where TestProject is the name of the project containing your unit tests.
When I have access to the source code, marking Internal methods visible is my preferred method of testing private methods. When I don't have access to source code, I tend only to test public methods.