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

Mockito = Stunt double for your dependencies

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).

Advertisement

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

MistakeWhat happensFix
Mixing a matcher with a raw value: when(repo.find(any(), 5))InvalidUseOfMatchersExceptionUse matchers for all arguments: eq(5)
Stubbing a method that the test never callsUnnecessaryStubbingException (strict stubs)Remove the stub, or mark it lenient() if it's shared setup
when(spy.method()) on a spyCalls the real method while stubbingUse doReturn(x).when(spy).method()
Mocking the class under testTests prove nothingMock only dependencies; use @InjectMocks for the real class
Mocking value objects or everythingBrittle tests tied to implementationMock boundaries (repositories, clients), use real simple objects