I was talking with a team last week about unit testing and TDD and the question came up as to whether private methods should be tested. I immediately said "no way" without any hesitation and was really surprised at the reaction from some of the team. We had a very interesting chat about it, and I thought I'd put down my thinking here as well to see what you think.
Firstly I see unit testing as black box testing. We should test our classes through their public and internal methods - i.e. from the viewpoint of a consumer of of the class; without any understanding of how that functionality may be implemented internally.
Next, the only reason for a class to have private methods is to support the public and internal methods of that class. If there are private methods that aren't reached through public or internal methods then you have dead code and it should be removed. Similarly, if you can't hit all of the code in your private methods through the public/internal methods then you have dead code in your method and it, likewise, needs to be removed.
Now, in order to test private methods your code needs to have some way of exposing those private methods to the test classes, meaning they can't actually be private methods in all situations. They need to be private for release builds, but accessible for test builds. You can try using compiler directives or some other mechanism to control accessibility however this is error prone and it's easy to accidentally release a version of an assembly with the private methods exposed as internal or public methods. More often though you'll simply see people writing exposing methods that really should be private just to make it easier to test. Not a design choice.
Further, tying tests to private methods makes your tests brittle. If start to refactor a class I should be free to make changes to the private methods without impacting the externally exposed functionality of the class. For example, if I rename an internal or public method I would expect tests to fail, but renaming a private method should have no impact on the tests and I would expect that they should continue to function correctly.
For me these reasons are reason enough.
So why would you want to test a private method? The argument is something like this "If my public method does a lot of work - e.,g. setting up connections to databases and so forth, and my private method is just doing a small piece of logic then I want to test that the logic is correct without needing to go through all the other work." It sounds like a reasonable argument but it's an argument that's only required when poor design decisions have been made.
A well designed class will do one thing and one thing only (the single concern principle) and will call out to other classes for functionality such as connecting to databases or file systems, etc. By using dependency injection and programming to interfaces you can make testing much simpler by passing mock objects to the class under test without actually needing to do the work of connecting to a database for instance. Not only does this help with the separation of concerns principle, but it also means my unit tests will actually be unit tests and not integration tests. And by using mock objects they'll also be a lot faster to run.
So, what do you think? Leave a comment if you agree or disagree. I'd like to hear your thoughts on the subject.