Resolving Mockito Spy Method Call Issues with doReturn() Solution

Nov 20, 2025 · Programming · 31 views · 7.8

Keywords: Mockito | Unit Testing | Spy Objects | doReturn Method | Java Testing

Abstract: This article provides an in-depth analysis of the issue where original methods are called when using when() with Mockito spy objects. Based on Q&A data and reference articles, it explains the root cause in when() method execution mechanism and presents the correct solution using doReturn() method. The article includes comprehensive code examples, principle analysis, and best practice recommendations to help developers avoid common Mockito pitfalls.

Problem Background and Phenomenon Analysis

When using Mockito for unit testing, developers often need to mock specific methods of existing objects while preserving the original behavior of other methods. In such scenarios, the spy() method becomes an ideal choice. However, as shown in the Q&A data, when attempting to stub methods on spy objects using the when().thenReturn() syntax, the original method gets unexpectedly called.

The specific issue manifests as: during the execution of Mockito.when(myClassSpy.method1()).thenReturn(myResults), the method1() method is actually invoked, which may cause exceptions or unexpected side effects. The fundamental reason for this behavior lies in Mockito's when() method工作机制——it needs to execute the target method first to record invocation information.

Root Cause Investigation

From official documentation and Q&A data, it's clear that this issue is not a bug but an inherent characteristic of Mockito's design. When using the when() method, Mockito needs to execute the target method to establish stub configuration. For spy objects, this means the real method gets called once.

The example from the reference article further validates this phenomenon: in the spy test, even after setting the return value, the System.out.println("only show when it doesn't beening mocked") in the original method is still executed. This indicates that during the stub configuration phase, the real method is indeed called.

Solution: The doReturn() Method

Mockito provides the doReturn() method as an alternative approach, specifically designed for stub configuration on spy objects. This method does not call the original method but directly sets the return value.

The correct usage is as follows:

final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.doReturn(myResults).when(myClassSpy).method1();

This syntax structure avoids calling the original method during the configuration phase, ensuring test stability and predictability. Here, doReturn() specifies the return value, while when() is used to specify the target method and object.

Code Examples and Comparative Analysis

To better understand the differences between the two approaches, let's create a complete test example:

public class MyClassTest {
    @Test
    public void testSpyBehavior() {
        // Create real object
        MyClass realInstance = new MyClassImpl();
        
        // Create spy object
        MyClass spy = Mockito.spy(realInstance);
        
        // Wrong approach: will call original method
        // Mockito.when(spy.someMethod()).thenReturn("mocked result");
        
        // Correct approach: use doReturn
        Mockito.doReturn("mocked result").when(spy).someMethod();
        
        // Verify stub works
        assertEquals("mocked result", spy.someMethod());
    }
}

In this example, if using the commented wrong approach, someMethod() would be called during configuration phase, potentially causing exceptions. The doReturn() approach completely avoids this issue.

Applicable Scenarios and Considerations

The doReturn() method is particularly suitable for the following scenarios:

It's important to note that while doReturn() solves the configuration phase call issue, during actual test execution, methods that are not stubbed will still invoke their original implementations. This is a key difference between spy objects and mock objects.

Best Practice Recommendations

Based on Q&A data and practical experience, we summarize the following best practices:

  1. For spy objects, prioritize using doReturn(), doThrow(), doAnswer() methods for stub configuration
  2. Establish unified Mockito usage standards within teams to avoid mixing different stub syntax styles
  3. In complex testing scenarios, consider using mock objects instead of spy objects to reduce unexpected behaviors
  4. Regularly consult Mockito official documentation to stay updated with the latest features and best practices

Conclusion

Mockito's spy functionality provides flexible partial mocking capabilities for unit testing, but requires proper understanding of its working mechanism. By using the doReturn().when() syntax instead of the traditional when().thenReturn(), developers can effectively avoid the issue of original method calls during configuration phase. This solution not only ensures test stability but also demonstrates the importance of deep understanding of testing frameworks.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.