पाठ 12 / 25

Argument Matchers and Advanced Stubbing

Use argument matchers, answers and doReturn-style stubbing correctly.

Flexible stubs

Stubs match calls by argument equality by default. Argument matchers relax this: any(), any(Order.class), anyString(), anyLong(), eq(value), argThat(predicate) and more from ArgumentMatchers. A rule that catches everyone once: if any argument uses a matcher, all arguments must use matchers, so write when(repo.find(eq("pen"), anyInt())), not find("pen", anyInt()). thenAnswer(invocation -> ...) computes the result from the actual arguments, useful for echoing input back or generating IDs. For void methods, and for spies where calling the real method during stubbing would be harmful, use the doReturn(...).when(mock).method(...), doThrow(...) and doNothing() family. Avoid over-general matchers such as any() everywhere: tests should still fail if the code passes the wrong argument. Prefer stubbing with specific values and verifying important arguments with captors.

Matchers, answers and void stubbing

All-or-nothing matchers, computed answers and doThrow for a void method.

@ExtendWith(MockitoExtension.class)
class InventoryServiceTest {

    @Mock StockRepository stock;
    @Mock EventPublisher events;

    @Test
    void reservesWhenEnoughStock() {
        when(stock.available(eq("pen"), anyString())).thenReturn(10);       // matchers for all args
        when(stock.reserve(anyString(), anyInt()))
            .thenAnswer(inv -> "R-" + inv.getArgument(0) + "-" + inv.getArgument(1));

        var service = new InventoryService(stock, events);
        String reservationId = service.reserve("pen", 3, "WH-PUNE");

        assertThat(reservationId).isEqualTo("R-pen-3");
    }

    @Test
    void publishFailureIsWrapped() {
        when(stock.available("pen", "WH-PUNE")).thenReturn(10);
        when(stock.reserve("pen", 3)).thenReturn("R-1");
        doThrow(new BrokerUnavailableException()).when(events).publish(any(StockReserved.class));   // void method

        var service = new InventoryService(stock, events);
        assertThatThrownBy(() -> service.reserve("pen", 3, "WH-PUNE"))
            .isInstanceOf(ReservationNotConfirmedException.class);
    }
}

Matchers are all or nothing

Mixing a raw value with a matcher, as in when(repo.find("pen", anyInt())), throws InvalidUseOfMatchersException. Wrap the raw value in eq("pen").

त्वरित जाँच: How do you stub a void method to throw an exception in Mockito?

  • doThrow(ex).when(mock).voidMethod()
  • when(mock.voidMethod()).thenThrow(ex)
  • mock.voidMethod().thenThrow(ex)
  • Void methods cannot be stubbed
Answer

doThrow(ex).when(mock).voidMethod() — when(...) needs a return value; void methods use the doThrow/doReturn family.