Compare registering Mockito's JUnit 5 extension with calling MockitoAnnotations.openMocks(this) in a setup method: what does the extension give you that the manual call does not, and when would you still choose the manual call?
answer
- extension = session; openMocks = fields only
- STRICT_STUBS: UnnecessaryStubbingException, PotentialStubbingProblem
- validateMockitoUsage after each test
- @Mock on method parameters — extension only
- openMocks for JUnit 4 / TestNG / shared base classes
basics
~20 sBoth create the annotated mocks per test. The extension additionally applies strict stubs (failing on unused or mismatched stubbings), validates Mockito usage after each test, closes the session for you, and can inject mocks as test-method parameters. openMocks does none of that but works in any framework and needs no extra artifact.
solid answer
~40 s`@ExtendWith(MockitoExtension.class)` (artifact `mockito-junit-jupiter`) opens a **Mockito session** around each test method. That gives you: annotated field initialization; `@Mock`-annotated **parameters** on test and lifecycle methods; **strict stubs** by default — unused stubbings fail with `UnnecessaryStubbingException` and an argument mismatch reports `PotentialStubbingProblem` instead of silently returning null; `validateMockitoUsage()` at the end, catching a misplaced `verify`/`when`; automatic cleanup; and tuning via `@MockitoSettings(strictness = …)`. `MockitoAnnotations.openMocks(this)` only creates the annotated fields, with default (non-strict) behaviour, and returns an `AutoCloseable` you are responsible for closing. To approximate strictness manually you would use `MockitoSession` via `Mockito.mockitoSession()`. Choose the manual call when the class must run under JUnit 4/TestNG, when a shared base class spans frameworks, or when you cannot add the Jupiter artifact. Otherwise the extension is the default for JUnit 5.
code
java · 13 lines@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.STRICT_STUBS) // the default
class CheckoutServiceTest {
@Mock OrderRepository repository;
@Test
void chargesOnce(@Mock PaymentGateway gateway) { // parameter mock
when(repository.findById(1L)).thenReturn(Optional.of(anOrder()));
new CheckoutService(repository, gateway).checkout(1L);
verify(gateway).charge(any());
}
}go deeper
Know both initialize the annotated fields and that the extension is the normal JUnit 5 choice.
Explain strict stubs, usage validation, parameter mocks and auto-cleanup as the extension's extras, and that openMocks is framework-agnostic.
Discuss migrating a legacy suite onto strict stubs, scoping leniency narrowly, and reproducing session semantics with MockitoSession where Jupiter is unavailable.
Argue strictness as a codebase policy: unused-stub and argument-mismatch failures are cheap defect detectors, so the default should be strict with documented, narrow exemptions.
## What each one actually does **`MockitoAnnotations.openMocks(this)`** is a single method call. It reflects over the given object's fields, creates a mock for each `@Mock`, a spy for each `@Spy`, an `ArgumentCaptor` for each `@Captor`, then constructs/populates any `@InjectMocks` target. It returns an `AutoCloseable` whose `close()` releases the mocks (important for the inline mock maker, which keeps a registry) and finishes the implicit session. It knows nothing about JUnit, so it applies no strictness policy and performs no post-test validation. **`@ExtendWith(MockitoExtension.class)`** wraps each test method in a `MockitoSession`. A session is Mockito's unit of "a set of mocks with a strictness policy, opened and then finished with validation". Concretely the extension: 1. Initializes the same annotated fields, per test method, on the correct test instance (including `@Nested` classes). 2. Resolves **parameters** annotated `@Mock` on test, `@BeforeEach` and `@AfterEach` methods — so a mock used by one test need not become a field. 3. Applies **`Strictness.STRICT_STUBS`** by default: - a stubbing never used by the test fails it with `UnnecessaryStubbingException`; - calling a stubbed method with arguments that do not match any stubbing raises `PotentialStubbingProblem` at the call site, instead of quietly returning null and failing later in an unrelated assertion; - `verify` on a call already covered by stubbing is reported as redundant in some cases. 4. Calls `Mockito.validateMockitoUsage()` at the end of each test, catching structurally broken usage such as an unfinished `when(...)` or a stray `verify(mock)` with no method call. 5. Finishes the session, releasing mocks — no `close()` to remember, no leak if a test throws. 6. Accepts **`@MockitoSettings(strictness = Strictness.LENIENT)`** on the class or method to relax the policy where a shared fixture over-stubs. ## The practical difference in day-to-day work Strict stubs are the substantive difference, and they change test quality. With `openMocks` alone, a stub whose arguments no longer match the production call simply returns null; the test then fails somewhere else with a message that points at the wrong place, or worse, still passes because the null happens to be tolerated. Under strict stubs, Mockito fails at the mismatched call and prints both the stubbed and the actual arguments. Unnecessary-stub detection likewise turns stale test code into a failure instead of decoration. The cost is that legacy suites often fail immediately when moved onto the extension. The right response is to fix the stubs, or scope leniency narrowly (`@Mock(lenient = true)` on the one over-stubbed fixture, or `@MockitoSettings(strictness = LENIENT)` on a specific class) rather than globally. ## When the manual call is still right - **The test does not run on Jupiter.** JUnit 4 and TestNG cannot register a Jupiter extension. - **A shared abstract base class serves both generations** during a migration; `openMocks` in a setup method is the common denominator. - **The `mockito-junit-jupiter` artifact is unavailable** in that module. - **Non-standard instantiation.** Some framework integrations construct or proxy the test instance in ways where an explicit call on `this` is simply easier to reason about. - **You want strictness without the extension:** `Mockito.mockitoSession().initMocks(this).strictness(STRICT_STUBS).startMocking()` in setup, `session.finishMocking()` in teardown, gives the same policy manually. ## Things to get right either way - **Do not use both.** Fields would be created twice; stubbing performed between the two initializations is lost. - **Close what you open.** `openMocks` hands you an `AutoCloseable` for a reason; store it and close it in `@AfterEach`. - **Do not initialize in `@BeforeAll`.** It is static and runs once; per-test isolation is the point. - **Spring Boot tests are a different world.** Spring's bean-replacing mock annotation is processed by the Spring test context, not by Mockito's extension; the two mechanisms should not be mixed for the same field. ## Interview framing A strong answer distinguishes *initialization* (both do it) from *session semantics* (only the extension). Name strict stubs, `UnnecessaryStubbingException`, `PotentialStubbingProblem`, `validateMockitoUsage`, parameter injection and `@MockitoSettings`; then give the honest reason to still call `openMocks` — framework independence — and mention `MockitoSession` as the way to get strictness without Jupiter.
- You move a legacy suite onto the Mockito JUnit 5 extension and dozens of tests fail with UnnecessaryStubbingException. How do you handle it?Treat each failure as information: a stubbing that no test path uses is usually leftover from a refactor, and deleting it is the right fix. Where a shared fixture legitimately over-stubs for a subset of tests, scope the exception narrowly with `@Mock(lenient = true)` on that mock, or `@MockitoSettings(strictness = LENIENT)` on the specific class. Avoid switching the whole module to lenient, which discards the signal everywhere.
- How do you get strict stubs if the test class cannot use the Jupiter extension?Use `MockitoSession` explicitly: `Mockito.mockitoSession().initMocks(this).strictness(Strictness.STRICT_STUBS).startMocking()` in setup and `session.finishMocking()` in teardown. That is exactly what the extension does internally, so you get the same unnecessary-stubbing and argument-mismatch reporting under JUnit 4 or TestNG.
saying these in an interview costs you the question
- Claiming the extension and openMocks are fully equivalent
- Not knowing the extension applies strict stubs by default
- Using both mechanisms in the same class
- Forgetting that openMocks returns an AutoCloseable that should be closed
- Confusing Mockito's extension with Spring's bean-replacing mock annotation