In Mockito every collaborator you build with Mockito.mock() is called a "mock". When you write when(...).thenReturn(...) versus when you write verify(...), which test-double role is that object actually playing, and why does it matter which one a given test uses?
answer
- mock() = mechanism, role = how the test uses it
- when/thenReturn → stub role, feeds input
- verify → mock role, the call IS the assertion
- stub queries, verify commands
- stub + verify same query = asserting twice
basics
~20 sMockito.mock() is only a mechanism. Stubbing with when/thenReturn puts the object in a stub role: it supplies input and your assertion checks the result. verify() puts it in a mock role: the call itself is the thing being asserted. Pick one role per collaborator.
solid answer
~50 sMockito names its factory `mock()` for everything, but the role is decided by how the test uses the object. - **Stub role** — you call `when(repo.findById(1L)).thenReturn(user)`. The double exists to feed the code under test a canned input. The assertion is on the *result* of the system under test: state-based verification. - **Mock role** — you call `verify(emailSender).send(msg)`. The interaction itself is the observable outcome, because nothing is returned and no state you can reach changes: interaction-based verification. Why it matters: verifying a call you already stubbed asserts the same fact twice and couples the test to *how* the code works rather than *what* it produces. If `findById` were not called, the stub would not return the user and the state assertion would already fail. Verification earns its place for outgoing commands with side effects — send, publish, save — and for proving something did *not* happen. Rule of thumb: stub queries, verify commands.
code
java · 16 lines@Mock UserRepository userRepository; // used as a stub here
@Mock EmailSender emailSender; // used as a mock here
@InjectMocks AccountService service;
@Test
void deactivatingAnAccountEmailsTheOwner() {
when(userRepository.findById(1L)).thenReturn(Optional.of(alice));
service.deactivate(1L);
// state-based: what the system produced
assertFalse(alice.isActive());
// interaction-based: the effect has no other observable trace
verify(emailSender).send(argThat(m -> m.to().equals("[email protected]")));
// NOT: verify(userRepository).findById(1L) -- already implied by the stub
}go deeper
Say plainly that when/thenReturn supplies canned input while verify checks that a call happened, and give one example of each.
Add the query/command rule and explain why stubbing and verifying the same query is redundant.
Discuss the cost of interaction-based tests under refactoring, when verification is unavoidable (void effects, proving absence), and how captors change the failure message.
Set the house style: which collaborator categories are verified, why blanket verifyNoMoreInteractions is banned, and how that policy keeps the suite refactorable as the code evolves.
## Mockito's naming hides a distinction the test still has Mockito exposes one factory, `Mockito.mock(Type.class)` (or `@Mock`), and calls the result a mock regardless of what you do with it. But a test double's role is not a property of how it was constructed — it is a property of how the test uses it. The same Mockito object can play different roles in two different tests. Two usages, two roles: ```java // stub role: the double supplies input when(userRepository.findById(1L)).thenReturn(Optional.of(alice)); String name = service.displayName(1L); assertEquals("Alice", name); // assertion is on the RESULT // mock role: the double records the outcome service.deactivate(1L); verify(emailSender).send(argThat(m -> m.to().equals("[email protected]"))); // assertion is on the CALL ``` In the first test the double is scaffolding: it exists so the code under test can reach its assertion. In the second the double *is* the assertion target, because sending an email has no return value and no state the test can inspect. ## Why the distinction has teeth **Double assertion.** Stubbing `findById` to return Alice and then also writing `verify(userRepository).findById(1L)` asserts nothing new. If the method had not been called, the stub could not have supplied Alice and the result assertion would have failed already. The verification is dead weight that makes the test longer and no stronger. **Coupling to implementation.** Verification pins down *how* the system under test does its job — which collaborator, which method, which arguments, sometimes how many times. That is legitimate when the interaction is the required behaviour (a message really must be published). It is a liability when the interaction is an incidental route to a result: caching a lookup, batching two calls into one, or switching to a different query method are all behaviour-preserving refactorings that break interaction-heavy tests for no reason. **Diagnostic quality.** A failed state assertion says "expected Alice, got null" — you learn what is wrong with the output. A failed verification says "wanted but not invoked" — you learn what the code did not do, which is only useful if the call was the point. ## The practical rule: stub queries, verify commands A useful separation, borrowed from command/query separation: - **Queries** — methods that return a value and whose purpose is to answer a question (`findById`, `getRate`, `isEnabled`). Stub them; assert on the result the system under test produces. Do not verify them. - **Commands** — methods that cause an effect outside the system under test and typically return `void` (`send`, `publish`, `save`, `charge`). Verify them; there is often nothing else to assert. Methods that do both (`save` returning the persisted entity) sit in the middle. Usually you stub the return so the flow can continue *and* verify the call, because persistence really is the required behaviour — that is a legitimate stub-plus-verify pair, unlike the redundant one above. ## Where verification is the only tool - `void` side effects: emails, event publication, metrics, audit logging. - Proving absence: `verifyNoInteractions(auditLog)` for a rejected request, or `verify(repo, never()).delete(any())`. There is no state-based way to assert that nothing happened. - Argument content of an outgoing call, captured with an `ArgumentCaptor` and then asserted with ordinary assertions — this is still interaction-based, but the assertions read like state assertions and usually give better failure messages than a complicated matcher. - Cardinality that is part of the contract: `verify(gateway, times(1)).charge(...)` in a test about not double-charging. ## Smells that follow from getting the role wrong - Verifying every stubbed query "for safety" — the classic over-specified test, brittle under refactoring. - Blanket `verifyNoMoreInteractions()` on every double, which turns every added call anywhere into a test failure and buries the intent of the test. - Tests with no assertion at all, only verifications, when the method under test does return something meaningful. - Naming that hides the role: calling a field `userRepositoryMock` when the test never verifies it makes the reader look for a verification that is not there. Naming it for the collaborator and keeping the usage consistent is cheaper documentation than a comment. ## What to say in an interview Start from "the tool has one word, the test has two roles", give the query/command rule, and then justify it: verification buys you observability for effects you cannot otherwise see, and costs you coupling to implementation detail. A candidate who can name that trade-off, rather than reciting "stubs don't fail tests, mocks do", is demonstrating the judgement the question is probing.
- A test stubs repository.findById(1L) and then also calls verify(repository).findById(1L). What would you say in review?The verification is redundant: if the method had not been called with that argument the stub would not have returned the value, so the assertion on the result would already have failed. All the extra line adds is coupling to the exact call shape, which breaks the test if the code later caches the lookup or fetches through a different query. I would delete the verification and keep the result assertion.
- When is verify() the only option available to you?When the collaborator's method returns nothing and leaves no state the test can reach — sending an email, publishing an event, emitting a metric, writing an audit record. It is also the only way to assert absence, such as verifyNoInteractions(auditLog) or verify(repo, never()).delete(any()), because no amount of state inspection proves that a call did not happen.
- How do ArgumentCaptor-based checks fit into this stub/mock split?A captor is still interaction-based verification — you are asserting about a call — but it moves the detailed checking out of matchers and into ordinary assertions on the captured object. That usually gives clearer failure messages than a large argThat lambda and keeps the verification about 'this command was issued', with the payload checked in normal assertion style.
saying these in an interview costs you the question
- "Mock and stub are the same thing because Mockito calls the class Mockito.mock"
- Verifying every stubbed query "to be safe"
- Believing verify() asserts state rather than an interaction
- Adding verifyNoMoreInteractions() to every test by default
- Writing tests that contain only verifications even when the method under test returns a meaningful value