Programming

Mockito Spy: Partial Mock Specific Methods Only

Use Mockito spy for partial mocking in Java to mock specific methods like getPrice() and getQuantity() while letting getValue() execute real logic in Stock class. Step-by-step guide with doReturn examples and JUnit tests.

1 answer 1 view

How to use Mockito to mock only specific methods in a class while allowing others to execute real implementation?

For example, in this Stock class, I want to mock the return values of getPrice() and getQuantity(), but have getValue() perform the actual multiplication using those mocked values:

java
public class Stock {
 private final double price;
 private final int quantity;

 Stock(double price, int quantity) {
 this.price = price;
 this.quantity = quantity;
 }

 public double getPrice() {
 return price;
 }

 public int getQuantity() {
 return quantity;
 }

 public double getValue() {
 return getPrice() * getQuantity();
 }
}

Current test using mock() fails because getValue() is also mocked and does not execute the real code:

java
@Test
public void getValueTest() {
 Stock stock = mock(Stock.class);
 when(stock.getPrice()).thenReturn(100.00);
 when(stock.getQuantity()).thenReturn(200);
 double value = stock.getValue();
 // Fails: assertEquals("Stock value not correct", 100.00*200, value, .00001);
}

What is the correct way to create a partial mock or spy in Mockito for this scenario?

To mock only specific methods like getPrice() and getQuantity() in your Stock class while letting getValue() run its real implementation, use a Mockito spy instead of mock(). Create it with spy(new Stock(100.0, 200)), then stub the desired methods using doReturn(100.0).when(stock).getPrice()—this avoids calling the real methods during stubbing. Now stock.getValue() multiplies the mocked values (100 * 200 = 20000), passing your test without issues.


Contents


What Are Partial Mocks in Mockito?

Ever run into a test where you need to fake just a couple methods but let the rest of the class do its thing? That’s partial mocking in a nutshell—and Mockito handles it brilliantly with spies. Unlike full mocks that stub everything by default (hello, your failing getValueTest), partial mocks let un-stubbed methods execute real code. Perfect for legacy classes or when getValue() depends on mocked inputs like price and quantity.

Why bother? In real-world scenarios, you might test business logic that chains method calls, but external factors (like a price service) need faking. The Mockito spy tutorial on Testim nails it: spies instrument real objects, tracking calls while overriding specifics. Your Stock example screams for this—mock the fields indirectly via getters, compute value for real.

But heads up: spies aren’t magic. They create a proxy around your instance, so constructors run first. Pass real args like new Stock(0,0) if needed, then override.


Mockito Spy vs Mock: When to Use Each

mock(Stock.class)? Fast, lightweight, stubs all by default. But it killed your test because getValue() got stubbed too—no multiplication happened. Spies flip that: spy(new Stock(...)) calls real methods unless you intervene.

Here’s a quick breakdown:

Feature Mock Spy
Default behavior Stubs everything Calls real methods
Creation mock(Stock.class) spy(new Stock(...))
Best for Pure fakes, no real logic Testing with some real impl
Overhead Low Higher (wraps real object)
Verification Interactions only Real calls + stubs

As this Stack Overflow comparison points out, spies shine for partial mocks since they mimic the object’s natural flow. Use mocks for collaborators (e.g., a PriceService). Spies? When the class under test has intertwined logic, like your getValue() relying on getters.

In practice, spies track real interactions too—verify(spy).getValue() works even on called-real methods. But if your class is final or has statics? Mocks win, or grab mockito-inline.


Creating a Mockito Spy: Step-by-Step

Ready to fix that test? Follow these steps for a Mockito spy setup. You’ll need JUnit 5 + Mockito (add mockito-junit-jupiter dependency).

  1. Instantiate the real object: Stock stock = new Stock(100.0, 200);—fields get set, but we’ll override getters.

No, spy wraps an existing instance: Stock stock = spy(new Stock(anyPrice, anyQty));. Args don’t matter much since we’ll stub getters.

  1. Stub with doReturn: Crucial! when(...).thenReturn() calls the real method during stubbing on spies, messing things up. Instead:
java
doReturn(100.0).when(stock).getPrice();
doReturn(200).when(stock).getQuantity();
  1. Call the method: double value = stock.getValue();—now it multiplies mocked returns!

  2. Assert and verify:

java
assertEquals(20000.0, value, 0.0001);
verify(stock).getPrice(); // Called once via getValue()

The Baeldung Mockito spy guide walks through similar list examples, but it translates perfectly to your Stock. Why doReturn first? Order matters on spies—when triggers real calls prematurely.

Test it in your IDE. Boom—passes every time.


Full Example: Partial Mocking the Stock Class

Let’s put it all together. Your Stock class stays unchanged. Here’s the complete JUnit 5 test:

java
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.MockedStatic; // If needed later

@ExtendWith(MockitoExtension.class)
class StockTest {

 @Test
 void getValueTest() {
 // Create spy with dummy constructor args (overridden anyway)
 Stock stock = spy(new Stock(0.0, 0));

 // Stub only specific methods
 doReturn(100.0).when(stock).getPrice();
 doReturn(200).when(stock).getQuantity();

 // Real getValue() now uses mocked values
 double value = stock.getValue();

 assertEquals(20000.0, value, 0.0001, "Stock value not correct");

 // Optional: Verify interactions
 verify(stock).getPrice();
 verify(stock).getQuantity();
 verify(stock, times(1)).getValue();
 }
}

This mirrors the classic Stack Overflow solution for your exact scenario—300+ upvotes can’t lie. getValue() calls the spied getters, grabs mocked values, multiplies. No more zero or NaN surprises.

Scale it: Add @Spy Stock stock; as a field for reuse across tests.


Alternative: Mock with CALLS_REAL_METHODS

Not sold on spies? Mockito’s mock(Stock.class, CALLS_REAL_METHODS) does partial mocking too. It starts as a full mock but executes real code unless stubbed.

java
Stock stock = mock(Stock.class, CALLS_REAL_METHODS);
when(stock.getPrice()).thenReturn(100.0);
when(stock.getQuantity()).thenReturn(200);

double value = stock.getValue(); // Runs real impl!
assertEquals(20000.0, value, 0.0001);

The official Mockito docs recommend this for simple cases. Pro: No constructor needed. Con: Still a mock under the hood—heavier for complex objects. Spies edge it out for stateful classes like Stock.

When to pick this? Quick tests or when spying chokes on finals/statics.


Using doReturn and Best Practices for Spies

doReturn isn’t just syntax—it’s spy survival. On spies, when(spy.getPrice()).thenReturn(100.0) invokes getPrice() during setup, returning the real value (your field). Chaos.

Instead, doReturn(100.0).when(spy).getPrice(); stubs without calling. JavaBullets tutorial demos this clearly.

Best practices:

  • Always doReturn/doThrow/doNothing on spies for stubbing.
  • Use thenCallRealMethod() to explicitly real-call a stubbed method: doReturn(50.0).when(spy).getPrice(); when(spy.getPrice()).thenCallRealMethod(); (rare).
  • Verify order: InOrder inOrder = inOrder(spy); inOrder.verify(spy).getPrice();
  • Fields? Spy doesn’t touch privates directly—mock getters/setters.
  • Refactor tip: The Mockito site warns partial mocks mask design issues. Extract getValue() to a pure function if possible.

Table for syntax clarity:

Intent Spy Syntax Mock Syntax
Stub return doReturn(x).when(spy).method() when(mock.method()).thenReturn(x)
Real method (default) when(mock.method()).thenCallRealMethod()
Void stub doNothing().when(spy).voidMethod() doNothing().when(mock).voidMethod()

Sticks, right?


Common Pitfalls and JUnit Integration

Spies bite back sometimes. Calling a stubbed method before stubbing? Real value sticks. Fix: Stub early.

Final methods? Default Mockito skips them—add mockito-inline dependency.

Constructor hell? Spy runs it: spy(new Stock(100,200)) sets fields, but stubs override.

JUnit 5 setup: @ExtendWith(MockitoExtension.class) + @Spy fields:

java
@Spy
Stock stock = new Stock(0,0);

@BeforeEach
void setUp() {
 doReturn(100.0).when(stock).getPrice();
 // etc.
}

Riptutorial example shows @Spy with @InjectMocks for services. Medium deep-dive covers differences too.

Pitfalls checklist:

  • Forgot doReturn? Real calls leak.
  • No verifies? Miss side effects.
  • Heavy spies slowing tests? Switch to mocks + thenCallRealMethod().

Nail these, and JUnit Mockito tests fly.


Sources

  1. Use Mockito to mock some methods but not others — Stack Overflow solution for exact Stock class partial mocking: https://stackoverflow.com/questions/14970516/use-mockito-to-mock-some-methods-but-not-others
  2. Mockito Spy — Baeldung tutorial with spy examples and doReturn usage: https://www.baeldung.com/mockito-spy
  3. Mockito Official Documentation — Spy definition, CALLS_REAL_METHODS, and best practices: https://site.mockito.org/
  4. What is the difference between mocking and spying — Stack Overflow comparison of spy vs mock mechanics: https://stackoverflow.com/questions/15052984/what-is-the-difference-between-mocking-and-spying-when-using-mockito
  5. Spy () for partial mocking — Riptutorial on @Spy annotations in JUnit: https://riptutorial.com/mockito/example/26038/-spy--for-partial-mocking
  6. Understanding Partial Mocking with Mockito — Medium article on spy vs mock differences: https://medium.com/@AbhineyKumar/understanding-partial-mocking-with-mockito-spy-vs-mock-and-their-key-differences-4fd9110c762b
  7. Mockito Spy — Testim blog on partial mocking use cases: https://www.testim.io/blog/mockito-spy/
  8. Mockito partial mocks — JavaBullets examples of doReturn on spies: https://www.javabullets.com/mockito-partial-mocks-mock-and-spy/

Conclusion

For partial mock Mockito scenarios like your Stock class, spies deliver: wrap a real instance, doReturn on getPrice() and getQuantity(), and watch getValue() compute 20000 cleanly. Ditch plain mock()—it stubs too much. Between spies and CALLS_REAL_METHODS, pick spies for authenticity unless finals block you.

This approach scales to complex services. Just remember doReturn order and verify interactions. Your tests? Solid now. Grab the code, run it—feel that green bar glow.

Authors
Verified by moderation
Moderation
Mockito Spy: Partial Mock Specific Methods Only