Extracting accessibility

Often times, applying the Extract Method refactoring technique results in the creation of a hip private method. This certainly creates an interesting testing challenge should you want to actually verify the behavior of that method in isolation. Of course, there are a number of ways to approach this issue:

  • Make the method public
  • Make the method protected and put the test case in the same package
  • Make an inner class, in the parent class, which is a test case

It turns out there is another option as well: leave the method as declared (i.e. private) and use the copasetic JUnit-addons project to test it.

The JUnit-addons project has a few handy utilities that facilitate testing with JUnit; however, definitely one of the most useful is its PrivateAccessor class, which makes testing private methods a snap, regardless of your chosen testing framework. The PrivateAccessor class has no implicit dependency on JUnit; therefore, it can be used in TestNG, etc.

The PrivateAccessor’s API is simple- by providing the name of the method (as a String) and its corresponding parameter types and associated values (in Class and Object arrays respectively) to the invoke method, the value of the invoked method is returned. Underneath the covers, the PrivateAccessor class actually turns off object accessibility using Java’s Reflection API. Keep in mind, however, that if your VM has custom security settings, this utility may not function correctly.

Below, the getStatus method, which has been declared as private in the AccountAction class, is called with both parameters values set to null. The invoke method returns an Object, hence the cast to a String. Also note, the invoke method declares that it throws Throwable, so you either must catch it or let your testing framework handle it, as I’ve done.

public void testGetStatus() throws Throwable{
  AccountAction action = new AccountAction();

  String value = (String)PrivateAccessor.invoke(action,
      "getStatus", new Class[]{IStatus.class, List.class},
       new Object[]{null, null});

  assertEquals("should be No Changes Since Creation",
    "No Changes Since Creation", value);
}

Note, the invoke method has been overridden to either take an Object instance as above or a Class in the case that the desired private method is also static.

Keep in mind that using reflection to invoke private methods does introduce a level of brittleness to the resulting tests. Should someone rename the getStatus method, the above test will fail miserably; however, if tests are run frequently, the appropriate changes can be made quickly to fix the test.

Testing private methods is sure to create a smokin’ debate; however, its nice to know that it can be easily done. Dig it?

Related odds and ends
 

2 Responses to “Extracting accessibility”

  1. on 16 May 2006 at 7:50 am kocka

    Hi!

    Why should one test private methods? It seems a very rare situation, isn`t it?

  2. on 27 May 2006 at 7:43 pm Andy

    Indeed, testing private methods is not a daily occurrence- I find I end up doing it when I’m refactoring big methods (that were coded without testing in mind).

Trackback this Post | Feed on comments to this Post

Leave a Reply