Explain Codes LogoExplain Codes Logo

Testing Private method using mockito

java
test-engineering
mockito
reflection
Alex KataevbyAlex Kataev·Jan 20, 2025
TLDR

The correct approach is to target the exposed behavior through public APIs to test a private method. Indicate reflection as a last resort, not first:

// Assume private method: private String secretMethod() // In true spy style, we'll infiltrate the method's privacy... Method method = MyClass.class.getDeclaredMethod("secretMethod"); method.setAccessible(true); // Kaboom! We've just bypassed a private method. String result = (String) method.invoke(new MyClass());

The public interface that leverages the private method should be the core of your focus. Apply reflection judiciously and cautiously.

Coping with objects & collaborations

When testing, ensure that you weigh up the association between objects more than the individual private methods. Vital and effective testing usually involves the assessment of interactions and outcomes. Instead of adjusting your private methods' access modifiers, which, let's admit, wrecks encapsulation, refactor the code to be more welcoming to testability.

Calling in the big guns: Powermock & Whitebox

In desperate and dire need of testing a private method? The PowerMock library - your savior, can be brought into the equation as it integrates well with Mockito. Powermock's Whitebox and MockPrivate features come to the rescue and test private methods:

PowerMockito.spy(myClassInstance); // Shh! I'm spying. On a secret method, no less! PowerMockito.verifyPrivate(myClassInstance).invoke("secretMethod");

Here, Whitebox swings in to mutate private fields optimally before invoking private methods:

Whitebox.setInternalState(myClassInstance, "privateFieldName", value); // It's as if the private field was never private at all...

Remain cautious though! PowerMock has ties with explicit test runners and versions of the Java Development Kit (JDK).

Spy, Stub, and Reflection

To reinforce your testing strategy, spy objects and reflection come into play when you need to verify how a private method interacts with others:

MyClass spy = Mockito.spy(myClassInstance); // Now we're cooking...with spies. Mockito.doNothing().when(spy, "privateMethod"); // The spy says "do nothing." And gets away with it. spy.publicMethod(); Mockito.verify(spy).privateMethod(); // Did anyone see that? The spy sneakily ensured everything was as it should be.

The above example checks the call to the private method within the flow of a public method without invoking the private logic.

The public behavior is the Hollywood Star

Instead of constantly being fixated on the private method itself, aim your lens at the public behavior that it triggers. Examine the public methods, their various impacts, and consequences. By doing this, you're making sure that the class's external contract is well-respected and the private methods fit right in with the public API.

Design remodeling for testability

Consider these pointers to tailor your classes for testability. Hidden business logic can be:

  • Extracted to a new class
  • Switched to "package-private" for easy testing
  • The focusing lens should primarily be on public methods

Reflection: the use & misuse

Carefully weigh the benefits against the drawbacks of apparent tactics like ReflectionTestUtils. The booby traps may lure you into fragility pitfalls and threaten the test suite's stability.

ReflectionTestUtils.invokeMethod(myClassInstance, "secretMethod"); // Open Sesame! Private method, I'm here.