Mockito creates fake versions of a class's dependencies so you can test the class on its own: no real database, payment gateway or email server. It's the standard mocking library for Java unit and service tests, and SDETs meet it when testing framework utilities or working in developer test suites.
In Simple Terms
When testing a class that talks to a database, you don't want to hit the REAL database every test. Mockito creates a 'fake' database object (mock) that pretends to work, so you can test your class in isolation — fast, reliable, no real DB needed.
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
UserRepository userRepo; // auto-created mock
@Mock
EmailService emailService;
@InjectMocks
UserService userService; // real class, mocks injected
@Test
void testGetUserById() {
// ── STUBBING: define mock behavior ──
User fakeUser = new User(1, "Alice", "alice@test.com");
when(userRepo.findById(1)).thenReturn(Optional.of(fakeUser));
when(userRepo.findById(99)).thenReturn(Optional.empty());
// Stubbing exceptions
when(userRepo.findById(-1)).thenThrow(new IllegalArgumentException("Bad ID"));
// ── CALL REAL CODE ──
User result = userService.getUserById(1);
// ── ASSERT ──
assertEquals("Alice", result.getName());
// ── VERIFY: was the mock called? ──
verify(userRepo).findById(1); // called exactly once
verify(userRepo, times(1)).findById(1); // same
verify(userRepo, never()).save(any()); // never called save
verify(emailService, atLeastOnce()).sendWelcome(any());
}
@Test
void testCreateUser() {
User newUser = new User(0, "Bob", "bob@test.com");
// Stub with argument matchers
when(userRepo.save(any(User.class))).thenReturn(newUser);
when(userRepo.existsByEmail(anyString())).thenReturn(false);
userService.createUser(newUser);
// ArgumentCaptor: capture what was passed to mock
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(userRepo).save(captor.capture());
assertEquals("Bob", captor.getValue().getName());
// Verify email was sent
verify(emailService).sendWelcome("bob@test.com");
}
@Test
void testDoAnswer() {
// doAnswer: custom behavior for void methods
doAnswer(invocation -> {
String email = invocation.getArgument(0);
System.out.println("Mock sending to: " + email);
return null;
}).when(emailService).sendWelcome(anyString());
userService.createUser(new User(0, "Eve", "eve@test.com"));
}
@Test
void testSpy() {
// Spy: real object with some methods mocked
List<String> realList = new ArrayList<>();
List<String> spy = Mockito.spy(realList);
spy.add("one"); // real method called
spy.add("two"); // real method called
assertEquals(2, spy.size()); // real: 2
// Override specific method
doReturn(100).when(spy).size();
assertEquals(100, spy.size()); // mocked: 100
}
}
What is the difference between @Mock and @Spy?
@Mock creates a completely fake object — all methods return defaults (null, 0, false) unless stubbed. @Spy wraps a REAL object — real methods are called unless you override specific ones. Use @Mock for dependencies, @Spy when you need mostly real behavior with some stubbing.
What is ArgumentCaptor in Mockito?
ArgumentCaptor captures the arguments passed to a mocked method, letting you assert on them. Useful when you want to verify not just that a method was called, but WHAT was passed to it. More flexible than verify(mock).method(expectedValue).
Setup
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId> <!-- brings mockito-core -->
<version>5.12.0</version> <!-- check Maven Central for the latest -->
<scope>test</scope>
</dependency>
Capturing Arguments
@Captor ArgumentCaptor<Email> emailCaptor;
@Test
void sendsWelcomeEmailToNewUser() {
userService.register("asha@example.com");
verify(emailService).send(emailCaptor.capture());
Email sent = emailCaptor.getValue();
assertEquals("asha@example.com", sent.to());
assertTrue(sent.subject().contains("Welcome"));
}
Use a captor when you need to check what was passed to a mock, not just that it was called.
Common Mockito Mistakes
| Mistake | What happens | Fix |
|---|---|---|
Mixing a matcher with a raw value: when(repo.find(any(), 5)) | InvalidUseOfMatchersException | Use matchers for all arguments: eq(5) |
| Stubbing a method that the test never calls | UnnecessaryStubbingException (strict stubs) | Remove the stub, or mark it lenient() if it's shared setup |
when(spy.method()) on a spy | Calls the real method while stubbing | Use doReturn(x).when(spy).method() |
| Mocking the class under test | Tests prove nothing | Mock only dependencies; use @InjectMocks for the real class |
| Mocking value objects or everything | Brittle tests tied to implementation | Mock boundaries (repositories, clients), use real simple objects |