rc3.org

Strong opinions, weakly held

Package scope and unit testing with Java

I have a Java unit testing question. First, let me describe a scenario. Let’s say I have a class called IncomeTaxReturn that includes a method, calculateRefund(). That method is public (meaning anybody can call it). I also have a bunch of other methods that are only used by calculateRefund() that package up bits of logic so that the code is easier to understand and to test. The class might include methods like calculateTotalIncome() or lookUpTaxRate().

The methods I’ve written to encapsulate bits of business logic produce a predictable output given a specific input, and I want to write tests for them. I may also have some tests for calculateRefund(), but having tests for the other methods is a good practice because it helps to isolate problems when performing regression tests later.

Most Java projects keep tests in a directory structure parallel to the source for the application itself, making it easy to leave out the unit tests when building the application for distribution or deployment to the server.

I feel like the best practice is to mirror the package names between your application source and your tests. So if my IncomeTaxReturn class is in gov.irs.incometax then I put TestIncomeTaxReturn in the same package, gov.irs.incometax, only in the test directory. Then I just make sure that all of the classes for the application and tests are in the classpath when I want to run my tests.

So here’s the question. If I were not going to write any tests for the methods I was talking about, I’d make those methods private. If I want to test them, how do I handle the scope?

I can’t leave them as private because then my test cases can’t run them. So now I have to alter my code not to improve the application, but to make testing easier.

Obviously I could make the methods public, but that strikes me as a bad idea. Suddenly a bunch of internal methods that are really implementation details are part of the public interface of my class. From a purity standpoint, that’s a bad idea because someone else may come along and wonder what kind of API you’re providing. From a laziness standpoint, this approach stinks because when I reference the class in my IDE, I have to sift through all of those methods when I’m auto-completing a method name.

Protected scope is out, because unit tests usually subclass a generic test case, not the classes they’re testing.

I could leave out the scope entirely, leaving the methods with the default (package) scope. As long as I follow the practice of putting my tests in the same packages as the classes they test, this approach works, and is probably the right answer.

Is there another approach that’s recommended? Or do people generally just test against the public interfaces of their Java classes rather than testing the private methods that test bits of the business logic?

5 Comments

  1. If IncomeTaxReturnTest is in the same package as IncomeTaxReturn (regardless of the package of the test’s superclass), the test will be able to create instances of IncomeTaxReturn and invoke protected methods.

  2. I never knew that members of the same package could call protected methods.

  3. Another approach is to make them protected, then extend their class to create a special “ForTesting” version, so “IncomeTaxReturnForTesting” that has methods allowing you to access them.

  4. @Rafe: indeed. Check the Sun page on access control modifiers. If you do not give a function an access modifier, the default is package-private, which is private except for to the local package (which I think is what you’re looking for).

Leave a Reply

Your email address will not be published.

*

© 2016 rc3.org

Theme by Anders NorenUp ↑