unit testing private methods

Projects that use nUnit extensively often debate whether or not to test private methods.  As one of our developers wrote, "In old C++ world we used to use 'friend' keyword to allow class FooTest to access ALL methods and fields of class Foo. This allowed us to perform 'white box' testing by verifying internal class state. This level of testing is preferable comparing to 'black box' testing, which tests only method outcome."
 
A similiar result could be achieved in C# by having the unit tests build into the same assembly as the classes they are testing and then to declare methods as 'protected internal' instead of protected and 'internal' instead of private.  By using a multi-file assembly (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconbuildingmulti-fileassembly.asp) the tests can be in a seperate dll, and still access the internal methods of the business objects.
 
However, Visual Studio does not offer good support for multifile assemblies. Multifile assemblies must be linked with the command-line Assembly Linker, which makes build scripts and processes more complex.

suggest that tests should be written only for the public methods. This offers several advantages:

  1. Users will use the public methods, so all functionality should be exposed there. - If there is code that doesn't affect a public method, you should take it out.
  2. Writing the tests against the interface improves the interface. - Users of the class have to program against the interface, if it isn't clear and easy to use, improve the interface. If you write tests against private methods, you may never notice that you don't have a public interface to perform some action.
  3. Tests are not tied to the internals of a class - If tests only test the public functionality, they won't have to be rewritten during performance tuning or other optimizations.
  4. If the tests are written against an interface, other classes that implement the same interface can be tested without changing the tests.

 

5 Comments

  • I've taken the approach you mentioned. I test the public interface to ensure the components do what I expect. Usually if something's wrong in one of the private methods the test for the public method "catches" the error.

  • The major advantage of testing private details, is that it will immediately pint to the place that is broken. If something is broken inside private portions of the code, then even if testing of public interface found that something is wrong, you migth spend hours trying to find where specifically you made (for example) "off-by-one" error

  • If the author of Alice in Wonderland was a developer, he might have written riddles like, "when is private also public."

    So far the debate on private vs. public testing has focused on the "public" being the entire outside universe and "private" being only with a class. But let me pose an alternative view. Suppose that the universe was reduced to that of an assembly.

    I recently started working again on a pet project that I wrote years ago, and in it I have some internal classes. These are supporting classes for the rest of the assembly. For one reason or another I chose not to make them publicly accessible to the world.

    Although they are not public to the world, they are public in the context of the assembly. Any class and method and property can access those internal classes, but are they testable.

    I like to place the unit tests in a separate project. I would like to be able to test those internal support classes, but I cannot without some work with reflection.

  • I was taught the way you've blogged although recently have been questioning it.

    We're using a Command pattern, with one public method, Execute. Within that method other commands may be called etc...

    We're finding we have to Mock an awful lot in order to make sure unnecessary code isn't hit. This becomes messy and unmanageable.

    I know people will argue we should refactor, but are code is quite clean, and broken down into lots of small commands. It's just that a command may call 4 others during execution.

    This is leading me to looking at other ways of testing, and possibly testing private methods.

  • Unit Testing should probably only be done against the public interface of a class - that's why xUnit frameworks do not allow you to test private operations. I try yo prevent errors from happening, but I also throw custom exceptions when needed and then test for them in the public methods in my unit tests.

Comments have been disabled for this content.