Friday, October 13, 2006

Inner Reflections - Using reflection to unit test a Java inner class

At work, I was given the title of "Unit Test Master" and I took it all a little too seriously, publishing a series of "Test Master Musings" newsletters. I found the whole thing hilarious, but I think it might have come off arrogant... a lot of my comedy doesn't work. Anyway...

Test Master Musings #1 - Inner Reflections

Recently, a citizen of the realm and I had the opportunity to work on some failing unit tests for a Java class. Beyond being an overly complicated test with permanent fixture setup, the issue we tackled was that the test failed when run as part of the complete test case but passed when run on its own.

This is a variation of the xUnit pattern called Erratic Test. The cause of this is usually a shared fixture, so we moved the test to the top of the TestCase so that it was the first test to run and, sure enough, the test passed all the time. Digging deeper, it turned out the class had a private static inner class called Section that had a static final List variable that aggregated a list of sections. The problem was that there was no way to ever reset the list. In production this is not a problem, but it is for us because we want to run the class several out in a row. We came up with three options:

1. Move the test to the top of the test case, where it will always pass
2. Make something public on Section to reset the variable
3. Use reflection to reset the variable between runs

We ruled out #1 because, although easy to implement, would not work if we ever wrote a second test for report groups. We ruled out #2 because our coding standard says to prefer reflection to changing visibility. That left us with #3 which was difficult to implement. Luckily, the inner class was static, which made it a little easier. Here is how we refactored this.

We changed Section to initialize the field using a static method instead of a variable declaration. We did this because it is easier to call a private method than manipulate a private variable, and it insulated us a little from variable changes. So this:

private static final LinkedList order = new LinkedList( );

became this:

private static LinkedList order = null;
static {
  initOrder();
}

private static void initOrder() {
  order = new LinkedList();
}


Called the init method using reflection from out unit test like so:

Class handlerClass = null;
Class[ ] classes = ClassUnderTest.class.getDeclaredClasses();
for (Class aClass : classes) {
  if (aClass.getName().equals("ClassUnderTest$Section")) {
    handlerClass = aClass;
    break;
  }
}

if (handlerClass == null) fail(“Error creating inner class”);
ReflectUtil.callMethod(handlerClass, “initOrder”);


A bounty of four copper pieces will be awarded to anyone who can think of a better way to do this.

Peace and Quality be Unto Thee,

The Unit Test Master

Looking at this now, I can think of two ways to make this better, so I'll award myself the copper.
  1. Uh, a static inner class that is untestable? Raise it to the top level!
  2. Using reflection to access private members of the system under test? Make the target package visible
Some test master I was!

4 comments:

christian posta said...

In your initial discussion, you obviated using option number two because you pondered that using reflection is preferable to altering the visibility of a member for testing purposes -- so using reflection would be preferable to changing the member to public.

Isn't changing the member from private to package visible also altering the visibility for testing purposes? Wouldn't you still prefer reflection?

Hamlet D'Arcy said...

This is a pretty old blog post and I'm not sure I agree with it anymore :)

I would say I prefer package visibility over reflection because it is simpler to write, simpler for tools to understand, and lives a longer life. However, saying reflection and package visibility are the only options is a false choice... what's wrong with just elevating the inner class? Inner classes (non-static) are a smell that the Single Responsibility Principle is being violated. I almost never use them anymore except in the most simple, value object case.

My advice: Write a static inner class and elevate it up to a top level class. Now it's testable!

christian posta said...

I absolutely agree with that, regarding the non-static inner classes. I guess I was just being more general regarding testing the value of private member variables. As implementation classes should conceal their implementation details, I think I would still use reflection in my tests than to raise the visibility higher. Thoughts?

Hamlet D'Arcy said...

For me, there is no difference between package visibility or reflection. Either way, you're coupling the tests to an supposedly hidden implementation detail of your system under test. With reflection, that coupling is hidden a little. In package visibility it is simple to see that the coupling is there.

I'd just go with package visibility because it's simpler.