How to properly call another method inside a mock object when using `doCallRealMethod()` in Mockito?

I’m trying to test a scenario in Mockito where one method inside a mock calls another real method from the same class.

Here’s a simplified version of my code:

protected Confirmation confirm() {
    Confirmation confirmation = new Confirmation() {
        @Override
        public void onConfirm() {
            doCancel();
        }
    };
    return confirmation;        
}

protected void doCancel() {
    // some logic
}

And my test:

@Test
public void test() {
    Panel panel = Mockito.mock(Panel.class);

    Mockito.doCallRealMethod().when(panel).confirm();
    Mockito.doCallRealMethod().when(panel).cancel();

    panel.confirm();

    Mockito.verify(panel).cancel();
}

The problem is, cancel() is never called. I suspect it’s because onConfirm() is part of an overridden method within an anonymous class and not triggered directly.

How can I correctly test that confirm() eventually calls doCancel() using doCallRealMethod() in Mockito - especially when dealing with such overridden inner methods?

I faced the same issue once - it’s tricky because the onConfirm() method in your anonymous class never actually gets executed during the test. When you call panel.confirm(), you’re just returning the Confirmation object but not invoking onConfirm() on it.

You need to explicitly trigger that call:

Confirmation confirmation = panel.confirm();
confirmation.onConfirm();

Then Mockito can verify that doCancel() was called:

Mockito.verify(panel).doCancel();

So the real fix isn’t in doCallRealMethod() itself - it’s just that your test never calls the inner method that leads to doCancel().

I ran into this with doCallRealMethod() before - it only helps you invoke the real implementation when you actually call the method on the mock. In your case, confirm() runs but onConfirm() isn’t automatically triggered.

Try this:

Mockito.doCallRealMethod().when(panel).doCancel();

Confirmation confirmation = panel.confirm();
confirmation.onConfirm();
Mockito.verify(panel).doCancel();

This way, doCancel() will execute as expected once onConfirm() is manually invoked. I had to step through with a debugger to realize the anonymous inner method doesn’t run automatically.

In my projects, I’ve stopped relying on doCallRealMethod() for these kinds of nested callbacks - it gets confusing fast. Instead, I spy the real object and only stub what I need. For example:

Panel panel = Mockito.spy(new Panel());
Confirmation confirmation = panel.confirm();
confirmation.onConfirm();
Mockito.verify(panel).doCancel();

Using a spy lets you test real logic and verify internal interactions without fighting with anonymous inner methods. Much simpler, and it behaves closer to how your actual code runs.