November 22, 2010

Testing Private Methods

Originally published 18 Nov 2006

How should I test my private helper methods? Well, I used to just expose the method by making it accessible to the unit test (typically by making it package scoped).

So if I had a method like this:

   private void someHelperMethod() {
   }

I'd expose it like this:

   /** Exposed for testing purposes only. */
   void someHelperMethod() {
   }

I'd laugh at people who used the <code>PrivateAccessor</code> of the JUnit-addons project or directly used reflection to get the method and do a <code>method.setAccessible(true)</code>. I'd think, "What's the big deal? Just change the access of the method. Then, you'll make things easier for your IDE when you want to do a method rename refactoring or just find references to this method."

I've recently hopped the fence and I'm now campaigning for the other side.

Now, before I get into the why, I should point out that red flags should have gone up after you read the first question of this entry. Testing private methods? Why would you do that? Believe me, as I've mentioned here , I think unit tests should focus on black box testing as much as is practically possible and therefore, you shouldn't be testing private methods. I'm also familiar with the argument, "You could perhaps move those private methods to a helper class and therefore, they wouldn't be private." But I still believe there are cases where it makes sense to (have and) test private methods. And in this blog, I'm talking about these exceptional cases.

So what are some exceptional cases? Think of a high level method specifying the steps of an algorithm or a method on a mediator/controller-like class collaborating with multiple objects. You did break that method up into smaller, easier to understand, more communicative methods as described here , didn't you? So which is easier: setting up the object under test and its collaborating objects (the fixture) and calling the private helper method directly; or setting up the fixture and calling the public, higher level method that does some processing before calling the private helper method? In the latter case, you surely had to do more set up to navigate down to the same entry point in the private method. If you didn't or it wasn't much more work, then I'm talking about a different context.

All right, so why the switch? Well, first off, the real intent is to make them private. Private leaves no doubt that the method isn't meant to be used outside the class.

Along with that is encapsulation. As multiprocessor systems become more mainstream, exploiting concurrency by multi-threading adds complexity to software development. Encapsulating as much as possible can only simplify reasoning about thread safety.

One final reason is that making things private helps static analysis tools like FindBugs and PMD better identify dead code that can be eliminated. "Hey, this method is private and it's not being called!" Keeping the code base lean and clean is a key to maintainability.

The biggest downside, as I've hinted at above, is doing things like renaming/changing the signature of the method, or just finding references to it. The IDE won't make the appropriate changes to the test or find the reference in the test. But you'll find this pretty quickly when you run the test and it fails. Hint: Maybe you should have changed the test first anyway.

So join me on this side and remember that testing privates is better meant for special cases.

No comments:

Post a Comment