Mockito
02 / 02

Verification & Argument Capturing

Verification & Argument Capturing

Verifying Calls

verify(repo).save(any(User.class));           // called at least once
verify(repo, times(2)).findById(1L);          // exactly 2 calls
verify(repo, never()).deleteById(anyLong());  // never called
verify(repo, atLeastOnce()).count();
verifyNoInteractions(emailService);           // nothing touched it at all
verifyNoMoreInteractions(repo);               // no calls beyond the ones already verified

ArgumentCaptor

@Captor
ArgumentCaptor<User> userCaptor;

@Test
void savesUserWithNormalizedEmail() {
  userService.register("Ada", "ADA@Example.com");

  verify(repo).save(userCaptor.capture());
  assertEquals("ada@example.com", userCaptor.getValue().getEmail());
}

doAnswer for Dynamic Behavior

when(repo.save(any(User.class))).thenAnswer(invocation -> {
  User u = invocation.getArgument(0);
  u.setId(42L);          // simulate DB assigning an id
  return u;
});

BDD Style (given/willReturn)

import static org.mockito.BDDMockito.*;

given(repo.findById(1L)).willReturn(Optional.of(user));

userService.getUser(1L);

then(repo).should().findById(1L);
// purely stylistic alias for when/verify — same underlying mechanics

Verification Anti-Patterns

Verifying every single interaction and exact argument couples tests to implementation details rather than behavior — a harmless internal refactor can break many such tests without any real regression. Reserve verify() for interactions that represent genuinely important side effects (an email sent, a record deleted); prefer asserting on return values/state otherwise.

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free