Thursday, October 06, 2005

Testing protected methods with JUnit 4

One of the pains of JUnit is testing protected methods. Public methods offer no impediment to testing, and private methods in well-designed classes can be ignored as implementation details called by the public methods. But protected methods are important for frameworks and central to the Template Method pattern; they need testing.

The most common ways to test protected methods that I've seen are to invoke the protected method with reflection, to use a private inner helper class which extends the class under test, and similarly to extend the class under test and change the access of the protected methods to public. All have their drawbacks.

Enter JUnit 4. No longer must test classes extend TestCase. Using annotations, the test framework finds and runs your test methods without inheritance, and static imports keep calls to assertTrue and friends looking clean and tidy.

Your test class itself can extend the class under test and access the protected methods without the need for reflection or a second, helper class. This is another blow struck for small, clean code thanks to JDK 5.

UPDATE: As Sam in the comments pointed out, one could just put the tests in the same package as the class under test. For silly reasons, I left this out of the list of workarounds.

3 comments:

Anonymous said...

Hoorah for Java 5! But wait... generics have completely negated all movement towards small, clean code. Damn you Java 5! Damn you to hell!

Brian Oxley said...

Indeed.

The argument made in the C++ community in this regards (generics in Java is akin to templates in C++) is that it increases the burden on the library developer with regards to types and type information, but decreases the burden on the application developer using libraries with fewer casts and greater type safety.

Welcome to fecal waist-deep angle-bracket hell, my friend. On your heads, dogs!

Brian Oxley said...

You know, Sam, that is perfectly true. I should have included on the list of workarounds, and when I set up a unit test structure, I usually do put the tests in the same package with the code (but in a different source tree). For the last year, I've been working in a group where they did not follow this practise and it slipped my mind. Thanks!