Verifying Interactions

verify

For methods that return nothing (sending email, publishing an event), check that the mock was called correctly with verify.

@Test
void sendsConfirmationEmailOnce() {
    when(productRepository.findById(1L)).thenReturn(Optional.of(phone));
    when(paymentGateway.charge(any(), any())).thenReturn(PaymentStatus.SUCCESS);

    orderService.placeOrder("ravi", 1L, 1);

    verify(emailSender, times(1)).send(eq("ravi"), contains("Order confirmed"));
    verify(productRepository).save(phone);                 // times(1) is the default
    verifyNoMoreInteractions(emailSender);
}

@Test
void noEmailWhenPaymentFails() {
    when(productRepository.findById(1L)).thenReturn(Optional.of(phone));
    when(paymentGateway.charge(any(), any())).thenReturn(PaymentStatus.DECLINED);

    orderService.placeOrder("ravi", 1L, 1);

    verify(emailSender, never()).send(any(), any());
}

ArgumentCaptor

@Captor ArgumentCaptor<OrderPlacedEvent> eventCaptor;

@Test
void publishesEventWithCorrectTotal() {
    // ... arrange stubs ...
    orderService.placeOrder("ravi", 1L, 2);

    verify(eventPublisher).publish(eventCaptor.capture());
    OrderPlacedEvent event = eventCaptor.getValue();
    assertEquals(new BigDecimal("31998"), event.total());
    assertEquals("ravi", event.customer());
}
Verification modeMeaning
times(n), never()exactly n / zero calls
atLeast(n), atMost(n)bounds
inOrder(a, b).verify(...)calls happened in this order
verifyNoInteractions(mock)the mock was never touched

Mock, Spy, Fake

KindWhat it isUse
Mock (@Mock)all methods return defaults unless stubbedexternal dependencies
Spy (@Spy)real object, some methods stubbedlegacy code, partial behaviour (use rarely)
Fakea simple working implementation (in-memory repository)when mocks get too complex

Tip: Do not mock what you do not own (e.g. HttpClient internals) or simple value objects — mock your own interfaces (PaymentGateway) and wrap third-party APIs behind them.