skip to content

Which strictness applies by default when mocks are managed by Mockito's JUnit 5 extension (@ExtendWith(MockitoExtension.class)), by the JUnit 4 MockitoJUnitRunner, and when you simply call Mockito.mock(...) with no runner or extension at all?

level: seniorimportance: should knowfreq 42%

answer

  1. MockitoExtension = STRICT_STUBS, per test method
  2. MockitoJUnitRunner = Strict alias, class-scoped unused-stub report
  3. Silent / Strict / StrictStubs runner variants
  4. rule().strictness(...) — set it explicitly
  5. bare Mockito.mock = no enforcement

basics

~20 s

The JUnit 5 MockitoExtension defaults to STRICT_STUBS. The plain JUnit 4 MockitoJUnitRunner defaults to its Strict variant, which reports unused stubbings once per test class but not argument mismatches; MockitoJUnitRunner.StrictStubs gives full strict stubbing. Bare Mockito.mock(...) with no harness enforces nothing.

solid answer

~50 s

Strictness is enforced by whatever owns the mock lifecycle, so the default depends on the harness. - **JUnit 5 `MockitoExtension`** — `Strictness.STRICT_STUBS`, applied **per test method**: unused stubbings and argument mismatches fail the individual test. - **JUnit 4 `MockitoJUnitRunner`** — an alias for `MockitoJUnitRunner.Strict`, which detects unused stubbings and reports them **at the end of the whole class**, but does not do the fail-fast argument-mismatch check. `MockitoJUnitRunner.StrictStubs` gives the full STRICT_STUBS behaviour; `MockitoJUnitRunner.Silent` disables the checks. - **`MockitoJUnit.rule()`** — a rule whose level you should set explicitly with `.strictness(Strictness.STRICT_STUBS)` rather than relying on a default. - **Bare `Mockito.mock(Foo.class)` / `MockitoAnnotations.openMocks(this)` with nothing else** — no strictness at all, because nothing hooks the end of the test to run the validation. The practical consequence: the same test can pass on JUnit 4 and fail after a JUnit 5 migration, and a shared `@BeforeEach` stubbing that only some tests use fails under the extension but not under the JUnit 4 runner.

code

java · 13 lines
java
// JUnit 5 — STRICT_STUBS by default, per test method
@ExtendWith(MockitoExtension.class)
class ServiceTest { @Mock Repo repo; }

// JUnit 4 — full strict stubs (plain MockitoJUnitRunner is class-scoped Strict)
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class LegacyServiceTest { @Mock Repo repo; }

// JUnit 4 with another runner — set the level explicitly
public class RuleBasedTest {
    @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
    @Mock Repo repo;
}

go deeper

for a junior

Know that the JUnit 5 extension is strict by default and that plain Mockito.mock has no checks; that is enough.

for a middle

Add the JUnit 4 runner variants and the rule, and be able to set the level explicitly in each.

for a senior

Lead with the scope difference (class vs method) and the migration wave of failures it causes, plus which mocks (e.g. Spring-managed) fall outside the extension.

for a principal

Talk about making the harness itself a policy — how you keep a large suite from silently containing unenforced pockets, and what you accept during migration.

## Strictness is owned by the lifecycle, not by the mock Unused-stubbing detection needs a moment *after* the test to ask "was every stubbing used?", and argument-mismatch detection needs Mockito to know which test is currently running. Both require something that brackets the test. That bracket is the JUnit 5 extension, the JUnit 4 runner or rule, or an explicit `MockitoSession`. Whichever one you use decides the default level. ## JUnit 5: MockitoExtension `@ExtendWith(MockitoExtension.class)` defaults to `Strictness.STRICT_STUBS`. Two details matter: 1. **The scope is the test method.** The extension starts a Mockito session before each test and finishes it after, so a stubbing declared in `@BeforeEach` and used by only three of five test methods fails the other two with `UnnecessaryStubbingException`. This is the single most common surprise when a team moves to JUnit 5. 2. **It is overridable** with `@MockitoSettings(strictness = Strictness.LENIENT)` on the class (or per mock with `@Mock(lenient = true)`). The extension also injects mocks into `@Mock`-annotated fields and can resolve mock parameters on test methods and constructors — but the strictness contract is the part that changes test outcomes. ## JUnit 4: runner variants `MockitoJUnitRunner` is an alias for `MockitoJUnitRunner.Strict`. That variant collects unused stubbings across the whole class and reports them **once, at the end of the class**. Because the scope is the class, a `@Before` stubbing used by *any* test in the class counts as used — exactly the case the JUnit 5 extension flags. It does not perform the fail-fast `PotentialStubbingProblem` check. The three variants: - `MockitoJUnitRunner.Silent` — no hygiene checks (LENIENT-like); the escape hatch for legacy classes. - `MockitoJUnitRunner.Strict` — unused-stubbing detection at class level; the default. - `MockitoJUnitRunner.StrictStubs` — full `Strictness.STRICT_STUBS`, including argument-mismatch failures. `MockitoJUnit.rule()` is the alternative when you already have another runner (Spring, Parameterized). Set its level explicitly: `@Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);` — being explicit here is worth more than remembering the default, and `rule().silent()` exists for the legacy case. ## No harness at all If you write `Foo foo = Mockito.mock(Foo.class);` in a plain test, or call `MockitoAnnotations.openMocks(this)` in a setup method and never close the returned `AutoCloseable`, there is no session bracketing the test. Nothing reports unused stubbings, nothing raises `PotentialStubbingProblem`, and the behaviour is effectively LENIENT. Candidates often assume Mockito 5 made strictness global — it did not. Mockito 5's headline change was the switch to the inline mock maker as default, not strictness. A related trap: `openMocks` returns an `AutoCloseable` you are expected to close (usually in `@AfterEach` or try-with-resources) to release mock references; with the inline mock maker this matters for memory, but it still does not add strictness. ## Practical consequences - **Migration surprises.** Moving a suite from `MockitoJUnitRunner` to `MockitoExtension` upgrades the level *and* narrows the scope from class to method. Expect a wave of `UnnecessaryStubbingException` from fat `@Before`/`@BeforeEach` fixtures, plus new `PotentialStubbingProblem` failures that expose real argument bugs. - **Mixed suites lie.** If half the codebase uses bare `Mockito.mock`, hygiene is unenforced there, so a "we use strict stubs" claim is only true for the classes with the extension. Enforcing the harness (via review or an ArchUnit-style rule) is what makes the policy real. - **Spring tests.** `@MockitoBean`/`@MockBean` mocks are managed by the Spring test context, not by the Mockito extension, so they do not get the extension's strict-stubs treatment; do not assume the same failures appear there. ## How to answer State the three defaults crisply, then add the scope difference (class-level for the JUnit 4 runner vs method-level for the JUnit 5 extension) — that detail is what separates someone who has migrated a real suite from someone who has read the enum.

  • A test class passed under MockitoJUnitRunner and fails with UnnecessaryStubbingException after moving to MockitoExtension. What changed?
    The scope of the check narrowed from the class to the individual test method. The JUnit 4 runner considers a stubbing used if any test in the class triggered it, so a @Before stubbing needed by only some tests was fine. The extension starts a fresh session per test method, so every test that does not use that shared stubbing now fails. The fix is to move the stubbing into the tests that need it, or mark it lenient.
  • Do mocks created with Spring's @MockitoBean get the extension's strict stubbing?
    No. Those mocks are created and managed by the Spring TestContext framework, not by MockitoExtension, so the extension's per-test session does not bracket them and its checks do not apply. If you want hygiene enforcement in that layer you have to rely on review or on keeping collaborator stubbing inside plain unit tests that do use the extension.

saying these in an interview costs you the question

  • Saying strictness is a global Mockito setting that Mockito 5 turned on everywhere.
  • Claiming bare Mockito.mock(...) enforces strict stubs.
  • Believing MockitoJUnitRunner does the argument-mismatch check — only the StrictStubs variant does.
  • Assuming the JUnit 4 runner and the JUnit 5 extension report unused stubbings at the same scope.
  • Thinking MockitoAnnotations.openMocks(this) adds strictness rather than just initialising fields.

context