Skip to main content

Package Scoping And Unit Testing

Posted by crazybob on July 19, 2005 at 4:28 PM PDT

Scopes are one of the first things we learn as Java developers. Public, private and even protected scopes are easy enough to grok, but package-private scope alludes many Java newbies. I remember confusion when I first read about package-private scope; "Why would I ever need that?" I learn by understanding, not memorization. Missing the necessary context, my brain failed to retain package-private scope the first time through: in one ear, out the other.

Even when developers do have the background necessary to understand package-private scope, I think its inconsistency with the other scopes leads to further confusion. If you want a public method, prefix the method signature with public. For a private method, use the private keyword. Protected, protected. If you want a package-private method... omit the keyword altogether. For example, use String foo() instead of private String foo(). Adding fuel to the fire, Java documentation often interchanges the terms "package-private," "package," and "default." I'm embarrassed to admit I once tried to use package-private as a keyword.

Many programmers don't know (or think) they need package scoping. They try to work around its absence. Some messily expose implementation classes as part of their public API. This clutters the Javadocs and increases the library author's maintenance burden; whether the author likes it or not, they should support clients who depend on these implementation classes. Using package scope prevents clients from creating dependencies on internal implementation classes in the first place.

A few programmers like to put their public API in one package and their private implementation in another. They attempt to hide the "private" package from the client by not publishing its API. From a security viewpoint, exposing your private package to your public package inherently exposes it to everyone else (including the client). This may fly for application code, but you must hold reusable libraries to a higher standard. Java provides no way to say, "make foo public, but only for this one other package." In addition, splitting your public API and implementation into two different packages confines you to class granularity, whereas package scoping enables you to mix public and package-private members in the same class.

Others use protected scope when they should use package scope. My skin crawls when I see Javadocs dusted with protected members (Struts anyone?). This solution suffers the same fate as making your internal implementation classes public. Unlike package scoped members, protected members are still part of the public API; clients can access them, and the fields and methods show up in the Javadocs.

Package scoping particularly shines during unit testing. Some programmers argue that you should only test through the public API. Don't be silly. Limiting your tests to the public API contradicts the spirit of unit testing and subjects you to unnecessary dependency pain. I prefer to isolate and limit the amount of code I test at one time, and test as close to the code as possible.

To expose a class member to a test without impacting the public API, put the test class in the same package as the code it tests. Make the member you wish to expose to the test package-private instead of private (i.e. delete the private keyword from the declaration). I've actually grown accustomed to using package-private scope instead of private by default. Less typing, less clutter. To prevent clients from putting their classes in the same package as yours and accessing your package-private members, Java supports package sealing.