What are the rules for the static factory method behind @TestBean, and how do you point to a non-conventional or external method?
answer
- static, no-arg, assignable return
- <field>TestOverride convention
- methodName for rename
- fqcn#method for external
- exactly one match or startup fails
basics
~20 sThe 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".
solid answer
~40 s@TestBean's replacement instance comes from a static, no-argument factory method whose return type is assignable to the overridden bean's type. By convention Spring looks for a method named <fieldName>TestOverride in the test class (searching the test class hierarchy and enclosing classes). If you want a different name, set the methodName attribute. To use a method in another class, set methodName to a fully-qualified reference "com.acme.Fakes#clock". Exactly one candidate method must resolve — zero or multiple matches cause a context-startup failure, so it's fail-fast. The method runs during context initialization to produce the fixture, which then replaces the bean everywhere it's injected. Note the method takes no parameters: it can't receive the original bean, so if you need to decorate the real instance you'd reach for @MockitoSpyBean instead.
code
java · 21 lines@SpringBootTest
class ReportTests {
// Non-convention local method name via methodName:
@TestBean(methodName = "buildClock")
Clock clock;
static Clock buildClock() {
return Clock.fixed(Instant.EPOCH, ZoneOffset.UTC);
}
// Reuse a shared factory in another class via fqcn#method:
@TestBean(methodName = "com.acme.test.Fakes#inMemoryRepo")
ReportRepository repository;
}
// Shared factory class
public final class Fakes {
public static ReportRepository inMemoryRepo() {
return new InMemoryReportRepository();
}
}go deeper
Remember static, no-arg, and the TestOverride naming convention.
Know methodName overrides the name and supports external fqcn#method references.
Explain fail-fast single-match resolution and the no-arg (can't wrap) limitation vs @MockitoSpyBean.
Design shared factory classes for reusable fakes and standardise their placement.
## Factory method contract For `@TestBean`, the replacement object is produced by a **static factory method** with these rules: - **`static`** — it's invoked without a test instance. - **No arguments** — it cannot receive the original bean or any dependency; it must construct the fixture itself. - **Return type assignable to the target** — the returned type must be compatible with the bean/field type. ## Method resolution 1. **Convention (default):** Spring looks for `<fieldName>TestOverride`. For `@TestBean Clock clock;` it seeks `static Clock clockTestOverride()`. The search covers the **test class and its superclasses/enclosing classes**. 2. **`methodName` attribute (same class):** `@TestBean(methodName = "buildClock")` uses a differently named local static method — handy when one method backs multiple fields or the convention name is awkward. 3. **`methodName` as an external reference:** `@TestBean(methodName = "com.acme.test.Fakes#clock")` points to a static method in **another class**, letting you centralise reusable fakes in a shared factory class. ## Fail-fast resolution **Exactly one** matching method must be found. Zero matches (typo, wrong signature) or an ambiguous set cause the `ApplicationContext` to **fail to start** with a clear error — you learn immediately, not via a mysterious NPE. ## When the factory runs The method executes during context setup, before the test body, so the fixture is present for every autowiring point. ## Important limitation Because the method is **no-arg**, it **cannot access the original bean**. There is no built-in way to wrap/decorate the real instance with `@TestBean`. If you need the real bean's behaviour plus overrides, use **`@MockitoSpyBean`** (a spy wraps the real bean). ## Gotchas - Non-static or parameterised method -> resolution failure. - Convention name mismatch -> failure unless `methodName` is set. - External reference must use the `fqcn#method` syntax exactly. - One shared factory can back several `@TestBean` fields via `methodName`.
- Can the factory method receive the original bean so you can wrap it?No — @TestBean's factory is no-arg and cannot see the original bean. For wrap/decorate semantics use @MockitoSpyBean, which spies on the real bean.
- What if two @TestBean fields need the same fake?Point both at one static factory via methodName (local name or fqcn#method); each field still resolves its own bean by type/name, but they can share the constructing method.
saying these in an interview costs you the question
- Believing the factory method can take the original bean as a parameter
- Making the method an instance (non-static) method
- Assuming a differently-named method is picked up automatically without methodName