skip to content

Mocking Collaborators & Test Fixtures

Replacing beans in a test context: Mockito mocks and spies, non-Mockito overrides, and test-only configuration classes. Interviewers ask because every bean you replace forks the context cache and slows the suite.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

20

What is @MockitoBean and what problem does it solve in a Spring test?

level: juniorimportance: must knowfreq 45%

answer

  1. Spring 6.2, replaces Boot @MockBean
  2. swaps a context bean for a Mockito mock
  3. injected into the field too — when().thenReturn()
  4. @Mock alone is NOT in the context
  5. reset between test methods (MockReset.AFTER)

basics

~10 s

@MockitoBean (Spring 6.2) is a test-field annotation that replaces a real bean in the loaded Spring ApplicationContext with a Mockito mock, so collaborators receive the fake and you control its behaviour with when(...).thenReturn(...).

solid answer

~40 s

@MockitoBean is a Spring Framework 6.2 test annotation (package org.springframework.test.context.bean.override.mockito) placed on a field of a @SpringBootTest / @ExtendWith(SpringExtension) test. It is the framework successor to Spring Boot's now-deprecated @MockBean. When the context loads, the bean-override machinery finds the matching bean (by type, or by the name attribute) and swaps it for a Mockito mock; that same mock is also injected into the annotated field so you can stub it with when(mock.call()).thenReturn(x) and later verify(mock). Any other bean that autowires that dependency gets the mock instead of the real implementation — perfect for isolating a slow, remote, or nondeterministic collaborator (a payment gateway, an email sender) while still testing through the real Spring wiring. Unstubbed methods return Mockito defaults (null, 0, empty).

code

java · 19 lines
java
@SpringBootTest
class OrderServiceTest {

    @MockitoBean
    PaymentGateway paymentGateway; // replaces the real bean in the context

    @Autowired
    OrderService orderService;     // gets the mock injected for PaymentGateway

    @Test
    void placesOrderWhenPaymentApproved() {
        when(paymentGateway.charge(any())).thenReturn(ChargeResult.approved());

        Order order = orderService.place(new Cart(/* ... */));

        assertThat(order.status()).isEqualTo(Status.PAID);
        verify(paymentGateway).charge(any());
    }
}

go deeper

for a junior

Know it replaces a context bean with a mock and is stubbed with when().thenReturn().

for a middle

Know it succeeds Boot's @MockBean, resolves by type or name, and is reset between tests.

for a senior

Contrast it with @Mock and unit-testing, and note it forces the real context to load.

for a principal

Weigh it against slice tests / pure unit tests for suite speed and context reuse.

## What it is `@MockitoBean` is an annotation added in **Spring Framework 6.2** as part of the TestContext Framework's *Bean Override* feature. Fully qualified: `org.springframework.test.context.bean.override.mockito.MockitoBean`. It is the **core-framework replacement for Spring Boot's `@MockBean`** (`org.springframework.boot.test.mock.mockito.MockBean`), which is deprecated as of Spring Boot 3.4. Because it now lives in the framework's `spring-test` module, it works in any Spring test — you no longer need Spring Boot. ## The problem it solves In an integration test you load a real `ApplicationContext` (via `@SpringBootTest`, `@WebMvcTest`, `@ExtendWith(SpringExtension.class)`, etc.). Some bean in that context is undesirable to exercise for real — it calls a remote API, sends email, is slow, or is nondeterministic. Plain Mockito's `@Mock` creates a mock **object** but does *not* put it into the Spring context, so any bean autowiring that dependency still gets the real one. `@MockitoBean` bridges that gap: it **removes the real bean and registers a Mockito mock in its place**, and injects the same mock into your test field. ## How it resolves which bean to replace - **By type (default):** the field's declared type is used. If exactly one bean of that type exists, it is replaced. - **By name:** set `@MockitoBean(name = "...")` (or `value`) when there are multiple candidates of the type, or to target a specific bean. - If **no** matching bean exists, by default `@MockitoBean` *creates a new bean* (the mock is added). Set `enforceOverride = true` to require that an original bean already exists (fails fast otherwise). - Can also be declared at **class level** with a `types` attribute to mock several types without one field each. ## Stubbing and defaults You drive the mock with standard Mockito: `when(repo.findById(1L)).thenReturn(Optional.of(entity));` or BDD style `given(...).willReturn(...)`. **Unstubbed** methods return Mockito's defaults — `null` for objects, `0`/`false` for primitives, empty collections/`Optional.empty()` for those return types. ## Reset between tests Spring registers `MockitoResetTestExecutionListener`, which **resets the mock between test methods** (default `MockReset.AFTER`). So stubs and recorded interactions do **not** leak from one `@Test` to the next — each method starts clean. ## Related annotations - `@MockitoSpyBean` — wraps the *real* bean in a Mockito spy (real methods run unless stubbed); replaces Boot's `@SpyBean`. ## When to use it Use it for integration/slice tests where you want the real Spring wiring but need to isolate one collaborator. For pure unit tests of a single class, prefer constructing the class with plain Mockito `@Mock` collaborators and **no** Spring context at all — that is faster.

  • How is @MockitoBean different from Mockito's plain @Mock?
    @Mock just creates a mock object in your test; it is not registered in the Spring context, so autowired collaborators still receive the real bean. @MockitoBean actually replaces the bean inside the ApplicationContext, so everything that depends on it gets the mock.
  • What does a @MockitoBean return for a method you never stubbed?
    Mockito's default answer: null for object returns, 0/false for primitives, and empty collections / Optional.empty() for those types.

saying these in an interview costs you the question

  • Thinking @Mock and @MockitoBean are interchangeable (the plain @Mock is never placed in the Spring context).
  • Believing stubs persist across test methods (they are reset by default, MockReset.AFTER).
  • Claiming @MockitoBean is a Spring Boot-only annotation — it is core Spring Framework 6.2.

context

open as a page

What is @MockitoSpyBean and how does it differ from @MockitoBean?

level: juniorimportance: must knowfreq 72%

basics

~20 s

@MockitoSpyBean wraps a real Spring bean in a Mockito spy: real methods run by default, but you can stub or verify them. @MockitoBean replaces the bean with a full mock whose methods do nothing until stubbed.

open as a page

What is @TestConfiguration and how does it differ from a regular @Configuration in a Spring test?

level: juniorimportance: must knowfreq 70%

basics

~20 s

@TestConfiguration is a special @Configuration used only in tests. It adds or overrides beans on top of your app's real configuration, instead of replacing it. A plain @Configuration found via scanning would replace the primary config.

open as a page

How do you stub a @MockitoBean, and what happens to its stubs and recorded interactions between test methods?

level: middleimportance: must knowfreq 38%

basics

~10 s

Stub with Mockito: when(mock.method(args)).thenReturn(value) (or given(...).willReturn(...)). By default Spring resets the mock after each test method, so stubs and verify() history do not leak between tests.

open as a page

What is @TestBean in Spring 6.2 and how do you use it to override a bean in a test?

level: juniorimportance: should knowfreq 22%

basics

~10 s

@TestBean (Spring 6.2) replaces a bean in the test's application context with an instance you build in a static factory method inside the test class. By convention the method is named <fieldName>TestOverride.

open as a page

Why should you use doReturn(...).when(spy) instead of when(spy...).thenReturn(...) with @MockitoSpyBean?

level: middleimportance: should knowfreq 58%

basics

~10 s

With a spy, when(spy.method()).thenReturn(x) actually calls the real method while setting up the stub, which can cause side effects or exceptions. doReturn(x).when(spy).method() stubs without invoking the real method.

open as a page

How do you use @MockitoSpyBean to verify a collaboration while keeping real behavior?

level: middleimportance: should knowfreq 55%

basics

~10 s

Annotate the collaborator field with @MockitoSpyBean, autowire the service under test, exercise it, then call Mockito verify(spy).method(args) to assert the real bean was invoked as expected — the real logic still runs.

open as a page

When would you choose @TestBean over @MockitoBean (or @MockitoSpyBean)?

level: middleimportance: should knowfreq 28%

basics

~20 s

Use @TestBean when you want a real hand-written fake/stub with deterministic behaviour and no Mockito. Use @MockitoBean for a Mockito mock you configure with when/verify, and @MockitoSpyBean to wrap a real bean and spy on it.

open as a page

How do you share test fixtures (test doubles, seed helpers) across multiple test classes using @TestConfiguration and @Import?

level: middleimportance: should knowfreq 55%

basics

~10 s

Put the fixture beans in a top-level class annotated @TestConfiguration, then add @Import(TestFixtures.class) to each test class that needs them. Because it's top-level, it isn't auto-scanned, so @Import is what wires it in.

open as a page

How do @TestConfiguration and test doubles behave inside slice tests like @WebMvcTest or @DataJpaTest, compared to a full @SpringBootTest?

level: middleimportance: should knowfreq 40%

basics

~20 s

Slice tests load only a narrow part of the context. A nested static @TestConfiguration in the test still applies, but auto-detection of other @TestConfiguration classes is limited, so you usually add fixtures with @Import. Collaborators outside the slice must be supplied as @MockBean or fake @Beans.

open as a page

How does @MockitoBean affect the Spring TestContext context cache, and why can overusing it slow a test suite?

level: seniorimportance: should knowfreq 25%

basics

~20 s

The set of bean overrides is part of the context's cache key (MergedContextConfiguration). Two test classes with different @MockitoBean declarations get separate cached ApplicationContexts, so heavy or varied use causes many contexts to load — slower startup and more memory.

open as a page

How does @MockitoBean decide which bean to replace, and what do the name and enforceOverride attributes control?

level: seniorimportance: should knowfreq 20%

basics

~20 s

By default it matches the bean by the field's type. If several beans share that type you must set name (or value) to pick one. If no bean matches, it normally registers the mock as a new bean; enforceOverride = true instead requires an existing bean and fails otherwise.

open as a page

What are the ApplicationContext-caching and performance implications of @MockitoSpyBean?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Each unique set of bean overrides makes Spring build and cache a separate ApplicationContext. Spread @MockitoSpyBean across many different test classes and you get more context builds, slowing the suite. Keeping override sets consistent lets tests share a cached context.

open as a page

What are the rules for the static factory method behind @TestBean, and how do you point to a non-conventional or external method?

level: seniorimportance: should knowfreq 20%

basics

~20 s

The factory method must be static, take no arguments, and return a type assignable to the bean. By default it's named <fieldName>TestOverride and lives in the test class; use methodName to choose a different name or an external class via "fqcn#method".

open as a page

When would you supply a fake as a @Bean in a @TestConfiguration versus using @MockBean (or @TestBean)? What are the trade-offs?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Use a hand-written fake @Bean in @TestConfiguration when you want real, deterministic behavior reused across tests. Use @MockBean/@TestBean when you want a per-test Mockito mock you stub and verify. Fakes favor stable behavior; mocks favor per-test control.

open as a page

Explain bean overriding and precedence when a @TestConfiguration defines a bean that already exists in the primary context. What errors can occur and how do you control which bean wins?

level: principalimportance: should knowfreq 35%

basics

~20 s

Since Spring Boot 2.1, defining a duplicate bean name throws BeanDefinitionOverrideException by default. To override in tests you either enable spring.main.allow-bean-definition-overriding=true, match by bean name so the test definition replaces the original, or use @MockBean/@TestBean which are built to replace beans safely.

open as a page

How does @TestBean select which bean to override, and what does the enforceOverride attribute control?

level: seniorimportance: nice to knowfreq 15%

basics

~20 s

By default @TestBean matches by the field's type. If several beans match, disambiguate with the name attribute (bean name) or a qualifier. enforceOverride (default false) controls whether a missing target is an error: false creates a bean if none exists, true fails when there's nothing to override.

open as a page

As a tech lead, when would you avoid @MockitoBean in favour of another testing approach, and how do you keep a large Spring suite fast?

level: principalimportance: nice to knowfreq 14%

basics

~20 s

Avoid @MockitoBean when a pure unit test (plain @Mock, no context) or a narrow slice test would do — it forces a full context and can fragment the context cache. Reserve it for integration tests that genuinely need real Spring wiring plus one faked collaborator.

open as a page

When is @MockitoSpyBean the wrong tool, and what are its limitations?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Avoid it when you're really testing implementation details, when the collaborator has an easy fake, or when the method you need to control is final/private (Mockito can't intercept those). Prefer real beans, test doubles wired via configuration, or a full @MockitoBean.

open as a page

What architectural considerations (context caching, replacing older override hacks) come with using @TestBean across a suite?

level: principalimportance: nice to knowfreq 12%

basics

~20 s

Bean overrides are part of the test context cache key, so each distinct set of @TestBean overrides yields a separate cached ApplicationContext. Overusing varied overrides fragments the cache and slows the suite. @TestBean also replaces older hacks like test @Configuration + @Primary or context customizers.

open as a page