When writing unit tests, one of the most repetitive tasks developers face is setting up mock objects. Traditionally, Mockito required explicit initialization using @Mock
annotations along with MockitoAnnotations.openMocks()
or the @ExtendWith(MockitoExtension.class)
mechanism. However, modern Mockito versions introduced inline mocks, making test setup cleaner and reducing boilerplate code.
This tutorial explores how inline mocks in Mockito work, why they matter, and how you can use them to write maintainable, production-ready test suites.
What Are Inline Mocks?
Inline mocks are a feature in Mockito (since version 2+) that allow the creation of mock objects directly without requiring separate setup or initialization. Instead of relying on global annotations or MockitoAnnotations
, mocks can be declared inline, making the test class shorter and easier to read.
Example – Traditional vs Inline Mocks
Traditional mock setup:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testFindUser() {
when(userRepository.findById(1L)).thenReturn(Optional.of(new User("Alice")));
assertEquals("Alice", userService.findUser(1L).getName());
}
}
Using inline mocks:
class UserServiceTest {
private UserRepository userRepository = mock(UserRepository.class);
private UserService userService = new UserService(userRepository);
@Test
void testFindUser() {
when(userRepository.findById(1L)).thenReturn(Optional.of(new User("Alice")));
assertEquals("Alice", userService.findUser(1L).getName());
}
}
Here, inline mocks remove the need for @Mock
annotations and extensions, keeping the test more explicit.
Why Inline Mocks Matter
Inline mocks simplify unit testing by:
- Eliminating boilerplate code (
@Mock
+ annotations setup). - Making tests more explicit and self-contained.
- Reducing coupling with JUnit or extension frameworks.
- Allowing ad-hoc mock creation inside specific test methods.
This makes inline mocks particularly useful in small test classes, quick prototypes, or isolated scenarios where dependency injection frameworks are not needed.
Real-World Importance
In production projects with CI/CD pipelines, inline mocks can:
- Speed up debugging: Since mocks are created where they are used, test readability improves.
- Reduce setup overhead: No need for extra
MockitoAnnotations.initMocks()
or JUnit extensions. - Increase portability: Inline mocks work seamlessly with JUnit 5, TestNG, or custom test frameworks.
Inline Mocks with Stubbing
You can still use all familiar Mockito operations (when
, thenReturn
, verify
) with inline mocks:
@Test
void testInlineMockStubbing() {
List<String> mockedList = mock(List.class);
when(mockedList.get(0)).thenReturn("Mockito Rocks");
assertEquals("Mockito Rocks", mockedList.get(0));
verify(mockedList).get(0);
}
Inline Mocks with Argument Matchers
Mockito’s argument matchers like any()
, eq()
, and argThat()
work the same way:
@Test
void testInlineMockWithMatchers() {
Map<String, String> mockedMap = mock(Map.class);
when(mockedMap.get(anyString())).thenReturn("default");
assertEquals("default", mockedMap.get("key1"));
assertEquals("default", mockedMap.get("key2"));
verify(mockedMap, times(2)).get(anyString());
}
Inline Mocks vs Annotations
Aspect | Inline Mocks | @Mock Annotations |
---|---|---|
Setup Overhead | Minimal – created directly | Requires annotation + init/extension |
Readability | High for small tests | Cleaner for large test classes |
JUnit/Framework coupling | Independent | Dependent on JUnit/MockitoExtension |
Flexibility | High – can create anywhere | Mostly used at class level |
Best Practices
- Use inline mocks for smaller, isolated tests where readability is key.
- Use
@Mock
annotations for larger projects with many dependencies to keep setup DRY. - Prefer inline mocks when migrating legacy tests for quick refactoring.
- Keep mock creation close to where it’s used for better context and clarity.
Version Tracker
- Mockito 1.x – Required
@Mock
andMockitoAnnotations.initMocks()
. - Mockito 2.x – Introduced inline mocks support.
- Mockito 3.x+ – Enhanced inline mocking (final classes, static methods).
- Mockito 4+ – Improved integration with JUnit 5 and modern Java.
Conclusion & Key Takeaways
Inline mocks in Mockito are a powerful tool for cleaner and more explicit test setups. While annotations still have their place in larger test suites, inline mocks provide flexibility and reduce overhead in many scenarios.
Key takeaways:
- Inline mocks = less boilerplate, more clarity.
- Great for small, focused tests.
- Use annotations in large projects where many mocks are shared.
- Works seamlessly with JUnit 5 and CI/CD pipelines.
FAQ
Q1: What is the difference between inline mocks and annotated mocks?
Inline mocks are created directly in code, while annotated mocks use @Mock
with initialization.
Q2: Can I use inline mocks with @InjectMocks
?
Yes, but typically inline mocks are passed directly to constructors instead of @InjectMocks
.
Q3: Are inline mocks faster than annotations?
Performance is nearly the same. The difference lies in readability and setup.
Q4: Do inline mocks work with argument matchers?
Yes, all matchers like any()
, eq()
, and argThat()
work normally.
Q5: Can inline mocks replace Testcontainers in integration tests?
No. Inline mocks are for unit testing; Testcontainers simulate real dependencies.
Q6: Do I need JUnit 5 for inline mocks?
No, inline mocks work with JUnit 4, JUnit 5, or TestNG.
Q7: Can inline mocks be used for spying?
Yes, spy()
can also be declared inline.
Q8: Do inline mocks help with flaky tests?
Indirectly – they reduce test complexity, which may help prevent flaky setups.
Q9: Are inline mocks good for microservices testing?
Yes, they work well for unit tests in microservice codebases, but integration still needs Testcontainers.
Q10: Should I use inline mocks in all tests?
Not always. Inline mocks shine in small, focused tests, while annotations are better in complex suites.