Sunday, June 5, 2016

Making Unit Testing Private Methods Easier

Earlier this year I blogged about testing private methods (here). I noted that FieldUtils utility from Apache Commons Lang product has one-line utilities to access private fields. While explaining to readers that Lang's MethodUtils utility should have a one-line utility to access private methods so that we can more easily test them directly. I explained that this is preferable to over-exposing those methods (e.g. making them protected) merely so they can be tested. 

As a result I filed LANG-1195 and contributed an enhancement for MethodUtils so that it can easily invoke private methods for testing. I'm happy to announce that my enhancement has been accepted and committed (Pull 141). Expect to see it in Commons Lang 3.5 when it's released.

Method Additions
Like FieldUtils, boolean forceAccess is true, private methods can be seen and executed through reflection. There is no need to set forceAccess to true for methods already visible (e.g. protected or public).  

These methods allow you to directly test private methods in unit tests. There's no longer a need for the common practice of making methods protected for the sole purpose of accessing them in unit test code. 

These methods really should only be used in unit test code. From an architectural perspective, production code should not be used to invoke methods that were never designed to be executed outside the context of that class. Some argue that private methods should not be tested directly as they are not exposed. As those of us with clients that have mandated 100% line, branch, and mutation coverage; we know that that's nearly impossible being restricted to testing private methods only through public or protected methods that use them.

Another argument against testing private methods is that it created a coupling between classes (the test class and the tested class) that was never meant to be. My response is that yes, it does create coupling. However, unit tests are very tightly coupled to their targets anyway. Secondly, it means that some code in private methods goes untested as testing them indirectly is too tedious and difficult.

These methods do not benefit from compile time checks. One of the reasons I don't advocate using these methods in production code is that they can't be checked by the compiler. Direct method execution can be checked as to syntax, accessibility, and correct parameter type usage. These methods bypass those two checks.

Specifically, methods added follow. If you use these, please let me know if you see issues or problems.

Invoke Private Method without Arguments
This is also patterned after the existing method invocation without the forceAccess option.

Method signature
invokeMethod(Object object, boolean forceAccess, String methodName)

This is used to invoke a private method in a class. Yes, the accessibility attribute on the method is temporarily set to true so that the invocation works, but it's set back to it's original after execution. A usage example is below.

Example 1
String result = (String)MethodUtils.invokeMethod(testBean, true, "myPrivateMethod");

Invoke Private Method with Arguments
This is also patterned after the existing method invocation without the forceAccess option.

Method signature
invokeMethod(Object object, boolean forceAccess, String methodName,Object... args);

Example 2

String result = (String)MethodUtils.invokeMethod(
    testBean, true, "privateStringStuff", "Hi There", 5, new Date());

No comments:

Post a Comment