Can Mockito create a partial mock with some real method behavior?

Is it possible, using Mockito, to create a partial mock where some methods are mocked but others retain their original behavior?

For instance, in the following Stock class, I want to mock the getPrice() and getQuantity() return values, but I want the getValue() method to execute the multiplication as defined in the Stock class:

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();
  }
}

In the following test code, I attempt to mock the getPrice() and getQuantity() methods but find that getValue() does not perform the calculation as expected:

@Test
public void getValueTest() {
  Stock stock = mock(Stock.class);
  when(stock.getPrice()).thenReturn(100.00);
  when(stock.getQuantity()).thenReturn(200);
  double value = stock.getValue();
  // The assertion fails because the mock Stock getValue() method does not use the Stock.getValue() calculation code.
  assertEquals("Stock value not correct", 100.00 * 200, value, .00001);
}

Use @Spy for Partial Mocks

You can use Mockito’s @Spy annotation to create a partial mock. This allows you to mock specific methods while keeping the original behavior of other methods.

Here’s how you can apply it:

import static org.mockito.Mockito.*;

public class StockTest {
  
  @Spy
  private Stock stock;

  @Test
  public void getValueTest() {
    // Mock the getPrice() and getQuantity() methods
    doReturn(100.00).when(stock).getPrice();
    doReturn(200).when(stock).getQuantity();
    
    double value = stock.getValue();
    // Assert the value using the real getValue() calculation
    assertEquals("Stock value not correct", 100.00 * 200, value, .00001);
  }
}

Use a Custom Mock with Delegation

If you prefer to create a mock with specific behavior but without using @Spy, you can use Mockito’s Answer to delegate method calls to a real instance:

import static org.mockito.Mockito.*;

public class StockTest {

  @Test
  public void getValueTest() {
    // Create a real instance
    Stock realStock = new Stock(100.00, 200);
    
    // Create a mock and use an Answer to delegate method calls
    Stock mockStock = mock(Stock.class, new Answer<Object>() {
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable {
        // Delegate calls to the real instance
        return invocation.getMethod().invoke(realStock, invocation.getArguments());
      }
    });

    // Mock the getPrice() and getQuantity() methods
    when(mockStock.getPrice()).thenReturn(100.00);
    when(mockStock.getQuantity()).thenReturn(200);
    
    double value = mockStock.getValue();
    // Assert the value using the real getValue() calculation
    assertEquals("Stock value not correct", 100.00 * 200, value, .00001);
  }
}