Mockito simplifies testing by allowing us to mock dependencies. However, in larger test suites, managing mock lifecycles becomes important. Sometimes you need to reset a mock, clear its interactions, or reuse it across multiple test cases. Done correctly, this keeps your tests clean, efficient, and reliable.
This tutorial covers resetting, clearing, and reusing mocks in Mockito, their differences, use cases, and best practices.
Why Manage Mock Lifecycles?
- Prevent State Leakage: Ensure one test’s behavior doesn’t affect another.
- Improve Test Readability: Keep tests focused by removing unnecessary noise.
- Support Reusability: Reduce boilerplate by reusing mocks.
- Ensure Stability in CI/CD: Avoid flaky tests caused by mock leftovers.
Think of mocks like whiteboards in a classroom: sometimes you erase interactions, sometimes you reset the whole board, and sometimes you keep the board but write over it.
Resetting Mocks with reset()
reset(mock)
removes all stubbing and interaction history.
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
class ResetMocksTest {
@Test
void shouldResetMock() {
List<String> mockList = mock(List.class);
when(mockList.size()).thenReturn(5);
System.out.println(mockList.size()); // prints 5
reset(mockList);
System.out.println(mockList.size()); // now returns 0 (default)
}
}
- Use when you want to reuse the same mock with completely fresh behavior.
- All stubs and verifications are cleared.
⚠️ Best Practice: Avoid overusing reset()
— it can make tests harder to read.
Clearing Interactions with clearInvocations()
clearInvocations(mock)
removes only the interaction history, not stubs.
@Test
void shouldClearInvocations() {
List<String> mockList = mock(List.class);
mockList.add("Hello");
verify(mockList).add("Hello");
clearInvocations(mockList);
// Still stubbed methods remain, but interactions reset
verify(mockList, never()).add("Hello");
}
- Keeps stubbing intact.
- Useful when verifying the same mock in multiple steps.
Resetting vs Clearing
Operation | Removes Stubbing | Removes Interactions | Use Case |
---|---|---|---|
reset(mock) |
✅ Yes | ✅ Yes | Start completely fresh |
clearInvocations() |
❌ No | ✅ Yes | Retain stubbing, clear history |
Reusing Mocks Across Tests
Instead of creating new mocks for every test, you can reuse mocks with JUnit 5 lifecycle annotations.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import static org.mockito.Mockito.*;
class ReuseMocksTest {
List<String> mockList;
@BeforeEach
void setUp() {
mockList = mock(List.class);
}
@Test
void testFirst() {
when(mockList.size()).thenReturn(10);
assert mockList.size() == 10;
}
@Test
void testSecond() {
when(mockList.isEmpty()).thenReturn(true);
assert mockList.isEmpty();
}
}
This ensures each test gets a fresh instance, avoiding test pollution.
Best Practices
- Prefer new mocks per test (cleaner and less error-prone).
- Use
clearInvocations()
for multiple verifications in a single test. - Use
reset()
only when absolutely necessary. - Don’t reset mocks in shared test fixtures — it leads to brittle tests.
- Document why a reset/clear is needed for clarity.
Mockito + Testcontainers
Mockito manages mock dependencies, while Testcontainers ensures real dependencies are tested. Use them together for hybrid testing:
import org.testcontainers.containers.PostgreSQLContainer;
@Test
void shouldStartDatabase() {
try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
postgres.start();
assert postgres.isRunning();
}
}
Version Tracker
- JUnit 4 → JUnit 5: Cleaner lifecycle management via
@BeforeEach
and extensions. - Mockito Updates: Enhanced APIs for
clearInvocations()
and better reset control. - Testcontainers Growth: Parallel test execution with isolated containers.
Conclusion & Key Takeaways
Managing mock lifecycles is critical for reliable, maintainable tests. Mockito provides flexible tools like reset()
and clearInvocations()
to control mock state.
Key Takeaways:
- Use
reset()
to start fresh. - Use
clearInvocations()
to keep stubbing but reset history. - Prefer creating new mocks per test for simplicity.
- Combine Mockito with Testcontainers for realistic pipelines.
FAQ
1. What’s the difference between reset() and clearInvocations()?reset()
clears everything, while clearInvocations()
only clears interaction history.
2. Should I reset mocks after every test?
No, create new mocks instead — it’s cleaner and safer.
3. Can I clear stubbing without resetting?
No, stubbing can only be removed by reset()
.
4. Does reset() affect spies?
Yes, it resets spies to their original state.
5. Can I reuse mocks across multiple test classes?
Yes, but initialize fresh ones per class or use dependency injection.
6. Is reset() a code smell?
Often yes — prefer fresh mocks per test unless you have a strong reason.
7. Can I reset multiple mocks at once?
Yes, reset(mock1, mock2, ...)
works.
8. Do resets slow down tests?
Minimal impact, but overuse complicates tests.
9. Should I reset mocks in CI/CD pipelines?
No, use test isolation instead.
10. How does Testcontainers complement Mockito?
Mockito isolates dependencies; Testcontainers validates real external systems.