What is @TestBean in Spring 6.2 and how do you use it to override a bean in a test?
answer
- Spring 6.2 bean override
- static <field>TestOverride() factory
- real fake, not a Mockito mock
- field type selects the bean
- instance field + static no-arg method
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.
solid answer
~40 s@TestBean is a Spring 6.2 bean-override annotation. You put it on an instance field of your test class; Spring finds the matching context bean (by the field's type) and swaps in an object you create yourself. That object comes from a static, no-argument factory method whose name, by convention, is the field name plus TestOverride (e.g. field pricingClient -> method pricingClientTestOverride). Unlike @MockitoBean, no Mockito mock is involved — you return a hand-written fake or stub, so it needs no Mockito dependency and behaves deterministically. It's part of the Spring TestContext framework, so it works under @SpringBootTest / SpringExtension like the rest of the test infrastructure. Use it when you want a real, controlled fixture (a fake gateway, a fixed Clock) rather than a mock you configure with when/verify.
code
java · 19 lines@SpringBootTest
class OrderServiceTests {
@TestBean
private PricingClient pricingClient; // overrides the context's PricingClient bean
// Convention: <fieldName>TestOverride, static, no args, compatible return type.
static PricingClient pricingClientTestOverride() {
return amount -> BigDecimal.TEN; // deterministic hand-written fake
}
@Autowired
OrderService orderService; // receives the fake via the shared context
@Test
void usesFakePricing() {
assertThat(orderService.quote()).isEqualByComparingTo("10");
}
}go deeper
Know it swaps a context bean for a fixture built in a static <field>TestOverride() method.
Know it's non-Mockito, by-type by default, and the method-name convention plus the static/no-arg rules.
Contrast with @MockitoBean/@MockitoSpyBean and know when a hand-written fake beats a mock.
Frame it as replacing @Primary/test-@Configuration hacks and understand context-cache impact.
## What it is `@TestBean` (introduced in **Spring Framework 6.2**, part of `org.springframework.test.context.bean.override`) is a *bean override* annotation. It lets a test replace a bean in the `ApplicationContext` with an instance the test itself supplies via a **static factory method**. It is the non-Mockito sibling of `@MockitoBean` and `@MockitoSpyBean`. ## The two pieces 1. **The annotated field** — a non-static instance field in the test class, e.g. `@TestBean PricingClient pricingClient;`. The field's **type** is used (by default) to locate the bean to override. 2. **The static factory method** — produces the replacement instance. By **convention** its name is the field name + `TestOverride` (field `pricingClient` -> method `pricingClientTestOverride`). It must be `static`, take **no arguments**, and return a type assignable to the bean/field type. ## How it works During context setup the TestContext framework registers a `BeanOverride` that intercepts the target bean definition and substitutes the factory-produced instance. The overridden bean is then injected wherever it is `@Autowired`, including into other beans in the context — not just the test field. So the whole context sees your fake. ## Why use it instead of a mock - You want a **real, hand-written fake/stub** (deterministic behaviour, no `when(...).thenReturn(...)` ceremony). - You want to avoid a Mockito dependency or Mockito's proxying limitations (e.g. final classes, records, sealed types). - Good for value-like collaborators: a fixed `Clock`, an in-memory repository, a canned HTTP gateway. ## Key terms - **Bean override**: replacing a context bean at test time without editing production `@Configuration`. - **Factory method**: the static method that constructs the fixture. - **By-type selection**: default matching strategy using the field type. ## Gotchas - Field must be an **instance** field; the factory method must be **static** and **no-arg**. - If the convention-named method is missing you get a startup error — the name must match exactly. - Overriding by type fails if the type is ambiguous (multiple candidates) — then you must add a `name` or a qualifier.
- What happens if you name the factory method something other than <fieldName>TestOverride?Spring can't resolve it by convention and context startup fails; you must either rename it to the convention or set the methodName attribute explicitly.
- Does the override affect only the test field or the whole context?The whole context — the bean definition is replaced, so every other bean that autowires that type receives your fake too.