mock() @Mock

Unit tests frequently need to isolate a class from the collaborators it uses. A repository, a service, a client, or a helper object should not really run during a focused test. Mockito is one of the most widely used libraries for creating test doubles that look like real objects but do nothing unless a test defines behavior.

Mockito offers two common ways to create such doubles: the static mock() method and the @Mock annotation. Both eventually produce a Mockito mock proxy, but they differ in syntax, initialization, and typical usage.

Creating a Mock with mock()

The mock() method is a static factory method in org.mockito.Mockito. It is called directly when a mock is needed. For example:

UserRepository repository = mock(UserRepository.class);

This approach is useful when the mock is created inside a method, during setup, or when the number or type of mocks may vary at runtime.

A typical setup might look like this:

public class UserServiceTest {

    private UserRepository repository;
    private UserService userService;

    @BeforeEach
    void setUp() {
        repository = mock(UserRepository.class);
        userService = new UserService(repository);
    }

    @Test
    void shouldReturnUserName() {
        when(repository.findById(1L))
            .thenReturn(new User(1L, "Alice"));

        User user = userService.getUser(1L);

        assertEquals("Alice", user.getName());
        verify(repository).findById(1L);
    }
}

The mock() approach has several strengths. The creation process is explicit, so readers can see where the dependency comes from. It works well for a small number of mocks or for tests that create mocks dynamically. However, it requires manual dependency injection, often through a constructor. It also does not enable strict stubbing by default unless extra configuration is added.

Using the @Mock Annotation

The @Mock annotation comes from org.mockito.Mock. It is usually placed on a test field and initialized by a Mockito-aware test runner or extension.

With JUnit 5, the common setup is:

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private UserRepository repository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldReturnUserName() {
        when(repository.findById(1L))
            .thenReturn(new User(1L, "Alice"));

        User user = userService.getUser(1L);

        assertEquals("Alice", user.getName());
        verify(repository).findById(1L);
    }
}

With JUnit 4, the runner might be used instead:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

    @Mock
    private UserRepository repository;

    @InjectMocks
    private UserService userService;
}

If no runner or extension is used, mocks can still be created manually:

@BeforeEach
void setUp() {
    MockitoAnnotations.openMocks(this);
}

The annotation-based style is often cleaner for tests with several collaborators. It reduces boilerplate and pairs well with @InjectMocks, which lets Mockito inject mocks into the object under test.

Comparing mock() and @Mock

Aspect mock() @Mock
Creation Explicit method call Annotation declaration
Initialization Not required Needs extension, runner, or openMocks
Injection Manual Can use @InjectMocks
Readability Can become verbose with many mocks Cleaner for multiple dependencies
Strict stubbing Usually needs extra setup Default in extension or runner
Best fit Few or dynamic mocks Multiple fixed dependencies

When to Use Each Approach

Use mock() when you need a mock inside a method, during setup, or for a quick isolated test. It gives you direct control and is simple to understand.

Use @Mock when a test class has several fixed dependencies, or when you want to avoid repetitive setup code. Pair it with MockitoExtension for JUnit 5 or MockitoJUnitRunner for JUnit 4. Add @InjectMocks when you want Mockito to assemble the dependencies automatically.

If @Mock fields are not initialized, they remain null, which can lead to NullPointerException. If you use mock(), you must create the mock and pass it manually.

For Spring Boot tests, remember that @MockBean is different from @Mock. @Mock creates a plain Mockito mock, while @MockBean replaces a Spring bean in the application context.

Final Thoughts

Neither mock() nor @Mock is inherently better. For small tests or dynamic mock creation, mock() is direct and predictable. For larger test classes with many dependencies, @Mock combined with @InjectMocks is often more concise and easier to maintain.

The choice depends on the test structure, the lifecycle of the mock, and the level of strictness you want. Understanding both approaches helps Java test authors write clearer and more reliable unit tests.