Contents

Spring Boot's spring-boot-starter-test includes Mockito. Standalone projects add mockito-junit-jupiter for JUnit 5 integration.

<!-- Spring Boot — Mockito already included --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Standalone --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>5.12.0</version> <scope>test</scope> </dependency>

Enable Mockito annotations in JUnit 5 tests by adding @ExtendWith(MockitoExtension.class) to the test class.

Create mocks with the @Mock annotation (preferred) or the programmatic Mockito.mock() call. Inject mocks into the class under test using @InjectMocks.

import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.Assertions; @ExtendWith(MockitoExtension.class) class OrderServiceTest { @Mock OrderRepository orderRepo; // Mockito creates a mock implementation @Mock EmailService emailService; @InjectMocks OrderService orderService; // Mockito injects the mocks above via constructor/setter/field @Test void placesOrder() { Order saved = new Order("o1", "Widget", 2); Mockito.when(orderRepo.save(Mockito.any())).thenReturn(saved); Order result = orderService.place("Widget", 2); Assertions.assertEquals("o1", result.id()); } } @InjectMocks tries constructor injection first, then setter injection, then field injection. Prefer constructor injection in your production classes — it makes the dependencies explicit and works reliably with @InjectMocks.

Use when(mock.method(args)).thenReturn(value) to define what a mock returns for a given call. Chain multiple thenReturn calls to return different values on successive invocations.

@Test void stubbingExamples() { UserRepository repo = Mockito.mock(UserRepository.class); // Always return the same value Mockito.when(repo.findById(1L)) .thenReturn(Optional.of(new User(1L, "Alice"))); // Return different values on successive calls Mockito.when(repo.count()) .thenReturn(0L) // first call .thenReturn(1L) // second call .thenReturn(2L); // third and subsequent calls // Compute a value dynamically with thenAnswer Mockito.when(repo.findById(Mockito.anyLong())) .thenAnswer(inv -> { long id = inv.getArgument(0); return Optional.of(new User(id, "User-" + id)); }); Assertions.assertEquals("User-42", repo.findById(42L).get().name()); }

Use thenThrow to make a mock throw an exception. For void methods use the doThrow(...).when(mock).method() syntax.

@Test void stubbingExceptions() { PaymentGateway gateway = Mockito.mock(PaymentGateway.class); // Throw on a non-void method Mockito.when(gateway.charge(Mockito.anyDouble())) .thenThrow(new PaymentException("Declined")); Assertions.assertThrows(PaymentException.class, () -> gateway.charge(50.0)); } @Test void stubbingVoidMethods() { NotificationService notifier = Mockito.mock(NotificationService.class); // void methods need doThrow/doNothing/doAnswer Mockito.doThrow(new RuntimeException("SMTP down")) .when(notifier).sendEmail(Mockito.anyString()); Mockito.doNothing() .when(notifier).sendSms(Mockito.anyString()); // explicit no-op (default for void) Assertions.assertThrows(RuntimeException.class, () -> notifier.sendEmail("a@b.com")); }

A @Spy wraps a real object. Unstubbed methods execute normally; stubbed methods return the configured value. Use spies sparingly — they often indicate a design that could be improved.

@ExtendWith(MockitoExtension.class) class PricingServiceTest { @Spy PricingService pricingService = new PricingService(new TaxConfig(0.2)); @Test void spyCallsRealMethodByDefault() { // Calls the real calculateBase() implementation double base = pricingService.calculateBase("Widget", 3); Assertions.assertTrue(base > 0); } @Test void spyCanStubSpecificMethod() { // Override just one method, rest are real Mockito.doReturn(100.0).when(pricingService).calculateBase(Mockito.anyString(), Mockito.anyInt()); double total = pricingService.calculateTotal("Widget", 3); // uses stubbed base Assertions.assertEquals(120.0, total); // 100 * 1.2 tax } } Always use doReturn(...).when(spy).method() syntax when stubbing spy methods — never when(spy.method()).thenReturn(...). The latter actually calls the real method during the stub setup, which can cause side effects or NPEs.

Use verify() to assert that a mock method was called with expected arguments, the right number of times, or in the right order.

@Test void verificationExamples() { UserRepository repo = Mockito.mock(UserRepository.class); AuditLogger audit = Mockito.mock(AuditLogger.class); UserService svc = new UserService(repo, audit); svc.deleteUser(42L); // Was called exactly once with this argument Mockito.verify(repo, Mockito.times(1)).deleteById(42L); // Was called at least once Mockito.verify(audit, Mockito.atLeastOnce()).log(Mockito.anyString()); // Was never called Mockito.verify(repo, Mockito.never()).save(Mockito.any()); // No other interactions happened on this mock Mockito.verifyNoMoreInteractions(repo); } @Test void verifyOrder() { DataSource ds = Mockito.mock(DataSource.class); Notifier notifier = Mockito.mock(Notifier.class); BatchJob job = new BatchJob(ds, notifier); job.run(); InOrder inOrder = Mockito.inOrder(ds, notifier); inOrder.verify(ds).connect(); inOrder.verify(ds).process(); inOrder.verify(notifier).send("done"); }

ArgumentCaptor captures the argument passed to a mock method so you can assert on it. Use it when you need to verify the exact object that was passed, not just whether the method was called.

@ExtendWith(MockitoExtension.class) class OrderServiceCaptorTest { @Mock OrderRepository repo; @Captor ArgumentCaptor<Order> orderCaptor; @InjectMocks OrderService orderService; @Test void capturesOrderOnSave() { orderService.place("Gadget", 5); Mockito.verify(repo).save(orderCaptor.capture()); Order saved = orderCaptor.getValue(); Assertions.assertEquals("Gadget", saved.product()); Assertions.assertEquals(5, saved.quantity()); Assertions.assertNotNull(saved.createdAt()); } }

Argument matchers let stubs and verifications match arguments flexibly. When using matchers, all arguments in the same method call must be matchers — mix matchers and literal values using eq().

UserRepository repo = Mockito.mock(UserRepository.class); // Common matchers Mockito.when(repo.findByEmail(Mockito.anyString())) .thenReturn(Optional.empty()); Mockito.when(repo.findByAgeGreaterThan(Mockito.intThat(age -> age >= 18))) .thenReturn(List.of(new User(1L, "Alice"))); // Mixing literal and matcher — use eq() for the literal Mockito.when(repo.findByNameAndCity(Mockito.eq("Alice"), Mockito.anyString())) .thenReturn(Optional.of(new User(1L, "Alice"))); // Custom matcher with argThat Mockito.verify(repo).save(Mockito.argThat( order -> order.quantity() > 0 && order.product() != null ));
MatcherMatches
any() / any(Class)Anything, including null
anyString(), anyInt(), …Any non-null value of that type
eq(value)Equals the given value
isNull() / isNotNull()Null / non-null
startsWith(str), contains(str)String prefix / substring
argThat(predicate)Custom predicate
intThat(predicate), longThat()Custom predicate for primitives