I have a class Panel with a method confirm() that internally calls doCancel() via an overridden onConfirm() in a Confirmation object:
```java
protected Confirmation confirm() {
Confirmation confirmation = new Confirmation() {
@Override
public void onConfirm() {
doCancel();
}
};
return confirmation;
}
protected void doCancel() {
// actual cancel logic
}
In my test, I mocked Panel and tried to call real methods:
@Test
public void test() {
Panel panel = Mockito.mock(Panel.class);
Mockito.doCallRealMethod().when(panel).confirm();
Mockito.doCallRealMethod().when(panel).doCancel();
panel.confirm();
Mockito.verify(panel).doCancel();
}
However, `doCancel()` is never invoked. How can I correctly test that calling `confirm()` triggers `doCancel()` while keeping `Panel` mocked?
The reason your doCancel() isn’t triggered is that confirm() creates a new Confirmation instance internally, and the overridden onConfirm() calls doCancel() on the real object. Since you’re mocking Panel, the doCancel() inside that mock isn’t automatically wired to the lambda inside Confirmation.
A solution is to spy the object instead of mocking it, so real methods are called unless explicitly stubbed:
Panel panel = Mockito.spy(new Panel());
// confirm() uses real implementation
panel.confirm();
// verify doCancel() is called
Mockito.verify(panel).doCancel();
Spying keeps real method` behavior, which is necessary when internal calls rely on the object itself.
You can still use doCallRealMethod() with a spy if you want some methods mocked and others real:
Panel panel = Mockito.spy(Panel.class);
// Use real implementation for confirm and doCancel
Mockito.doCallRealMethod().when(panel).confirm();
Mockito.doCallRealMethod().when(panel).doCancel();
// Call the method
panel.confirm();
// Verify internal call
Mockito.verify(panel).doCancel();
Here, spy() ensures that when confirm() calls doCancel(), it hits the real method, unlike a pure mock where internal calls don’t execute real logic.
If you want to stick with a pure mock, you can’t rely on internal calls triggering real methods automatically. One workaround is to override the method inside the mock manually:
Panel panel = Mockito.mock(Panel.class);
Mockito.doCallRealMethod().when(panel).confirm();
Mockito.doAnswer(invocation -> {
// manually invoke real doCancel
invocation.callRealMethod();
return null;
}).when(panel).doCancel();
panel.confirm();
Mockito.verify(panel).doCancel();
This approach works, but it’s more cumbersome than using a spy. Personally, I usually go with a spy whenever internal method calls need to execute real logic.