skip to content

What does Mockito's doCallRealMethod() do, and how does using it on a plain mock differ from creating a spy over a real instance?

level: seniorimportance: nice to knowfreq 32%

answer

  1. mock = fake by default, opt one method into real
  2. spy = real by default, opt out per method
  3. mock built without constructor → fields null/0
  4. spy copies fields from a real instance
  5. abstract/template methods = the honest use case

basics

~20 s

doCallRealMethod() makes one stubbed method run its real implementation. On a plain mock the object was created without running any constructor, so its fields are null or zero and the real method often fails; a spy copies a fully constructed instance's state, so real methods usually work.

solid answer

~50 s

`doCallRealMethod().when(mock).compute()` flips a single method on an otherwise-empty mock to run its actual body — the opposite default from a spy, which runs everything real except what you stub. The crucial difference is **state**. A mock is instantiated without invoking any constructor (Mockito uses Objenesis), so every field is `null`/`0`. If the real method touches a field, you get a `NullPointerException` from inside production code. A spy is built from an object you constructed yourself, and Mockito copies its fields into the proxy, so real methods find initialised state. So `doCallRealMethod()` is best when the method is essentially stateless — an abstract class's concrete template method, a default interface method, a pure computation: ```java AbstractHandler h = mock(AbstractHandler.class); doCallRealMethod().when(h).handle(any()); doReturn("ok").when(h).doWork(any()); ``` Both are partial mocking. If more than one or two methods need it, extract a collaborator instead — the class is doing two jobs.

code

java · 8 lines
java
AbstractImporter importer = mock(AbstractImporter.class);

doCallRealMethod().when(importer).importAll(any());
doReturn(List.of(row)).when(importer).readRows(any());

importer.importAll(source);

verify(importer).persist(row);

go deeper

for a junior

Recall the definition — one method of a mock runs its real body — and that a spy is the opposite default.

for a middle

Explain the constructor-bypass consequence: fields are null on a mock, so the real method must not depend on state, whereas a spy carries copied state.

for a senior

Name the legitimate use cases (abstract template methods, default interface methods, pinning legacy code), the spy-is-a-copy semantics, and the withSettings().useConstructor escape hatch.

for a principal

Argue the design position: partial mocking marks a class with two responsibilities; extracting the suppressed part into an injected collaborator removes the need entirely, and repeated use in a suite is a refactoring backlog signal.

## The two ways to get partial mocking Mockito gives you two routes to an object where *some* methods are real and some are faked, and they differ in their default. **Spy** — real by default, fake where stubbed: ```java OrderService spy = spy(new OrderService(repo)); doReturn(0).when(spy).discount(); // only this is faked ``` **Mock plus `doCallRealMethod()`** — fake by default, real where you say so: ```java OrderService mock = mock(OrderService.class); doCallRealMethod().when(mock).total(); // only this is real ``` The second is the safer default for a class with dangerous methods, because nothing real runs unless you opt in method by method. ## Construction is the decisive difference A Mockito mock is not built by calling a constructor. The mock maker generates or instruments a type and instantiates it through Objenesis, bypassing constructors entirely. Consequences: - Every instance field is at its JVM default: `null` for references, `0`/`false` for primitives. - Field initialisers and constructor logic never run. - Collaborators injected through the constructor are `null`. So a real method invoked via `doCallRealMethod()` executes against an uninitialised object. If it reads `this.repository`, you get an NPE thrown from production code, and the stack trace looks alarming until you remember why. There is a partial workaround — `mock(Foo.class, withSettings().useConstructor(args))` runs a real constructor — but it is fiddly and rarely worth it. A spy is different: you construct the object yourself, and Mockito creates the proxy and **copies the real object's fields into it**. State is present, so real methods behave normally. Note the copy semantics: the spy is a distinct object, so mutations made through the spy do not appear on your original instance, and any code holding a reference to the original will not see stubbed behaviour. ## Where doCallRealMethod genuinely fits **Abstract classes and template methods.** You want to test the concrete algorithm in an abstract base without writing a test subclass: ```java AbstractImporter importer = mock(AbstractImporter.class); doCallRealMethod().when(importer).importAll(any()); doReturn(List.of(row)).when(importer).readRows(any()); ``` `importAll` runs for real and its abstract hooks are stubbed. Whether this beats a small hand-written test subclass is a taste call — the subclass is usually clearer, but the mock avoids maintaining another class. **Default interface methods.** A `default` method that composes other interface methods can be exercised the same way, with the abstract members stubbed. **Pinning legacy code before refactoring.** For a class you cannot restructure yet, opting exactly one method into real behaviour gives you a characterisation test without the risk that a spy's other real methods do something destructive. ## What it does not solve `doCallRealMethod()` on a method that depends on constructor-injected collaborators will fail, and no amount of stubbing the *other* methods helps, because the failure is a null field, not a call. Likewise, static and final concerns are mock-maker questions, not something this API addresses. ## Interaction with verification An invocation that runs the real body is still recorded, so `verify(mock).total()` works exactly as usual. What is *not* recorded reliably is what the real body calls on itself — internal self-invocation dispatch is an implementation detail you should not build tests on. ## Design perspective Every partial mock is an admission that the class under test contains a piece you want to run and a piece you want to suppress. Occasionally that is unavoidable — a framework base class, a third-party type, legacy code under characterisation. Usually it means the suppressed piece is a separate responsibility that wants to be a collaborator: extract it behind an interface, inject it, and the test becomes a plain mock with no partial-mocking machinery at all. Mockito's own documentation carries this warning, and it is worth repeating in an interview: reaching for `doCallRealMethod()` twice in the same test is a design signal, not a technique to master. ## Summary `doCallRealMethod()` opts one method of an otherwise-inert mock into real behaviour. Because the mock was created without a constructor, that method must be effectively stateless to work. A spy inverts the default and carries real state, which makes it more forgiving and more dangerous at the same time. Both are partial mocking; both are a last resort behind restructuring the class.

  • Why does a real method invoked on a plain mock so often throw NullPointerException?
    Because Mockito instantiates mocks without running any constructor — the mock maker creates the instance via Objenesis — so every field sits at its JVM default: null for references, zero for primitives. Field initialisers and injected collaborators never materialise. Any real method that touches instance state therefore dereferences null. A spy avoids this because it copies the fields of an object you constructed yourself.
  • Does mutating a spy change the original object it was created from?
    No. Mockito creates a separate proxy instance and copies the real object's fields into it, so the spy and the original are distinct objects from that point on. Changes made through the spy are invisible to the original, and any production code still holding the original reference will see real, unstubbed behaviour. This surprises people who expect the spy to wrap the instance by delegation.

A spy is a stand-in dressed in the real actor's costume and carrying their props; a mock with doCallRealMethod is an empty mannequin you asked to perform one line — fine if the line needs no props, a disaster if it does.

saying these in an interview costs you the question

  • Expecting a real method on a plain mock to see constructor-initialised fields
  • Thinking a spy delegates to the original object rather than to a field-copied proxy
  • Treating partial mocking as a normal design rather than a last resort
  • Claiming doCallRealMethod cannot be used with abstract classes
  • Believing invocations that run the real body are not recorded for verification

context