JUnit Extensions
The juneau-bct module bundles a small JUnit 5 extension for test-time bean injection — swapping production beans with test doubles inside a Juneau BeanStore for the duration of a JUnit 5 test, without modifying production code and without proxying. It is the Juneau-flavored answer to Spring's @TestConfiguration / @MockBean.
The extension lives in the org.apache.juneau.bct.junit package and centers on three types:
- JuneauBeanStoreExtension — the JUnit 5
Extension, registered via@ExtendWithor@RegisterExtension. - TestBean — the field/method annotation that declares an override.
- TestBeanStore — the overlay bean store, resolvable as a test-method parameter.
Quick start
import static org.junit.jupiter.api.Assertions.*;
import org.apache.juneau.bct.junit.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.*;
@ExtendWith(JuneauBeanStoreExtension.class)
class MyServiceTest {
@TestBean
ExternalApi mockApi = () -> "test-double";
@Test
void resolvesTheTestDouble(TestBeanStore store) {
assertSame(mockApi, store.getBean(ExternalApi.class).orElseThrow());
}
interface ExternalApi { String describe(); }
}
Two wiring modes
- Mode INJECT (default) — construction-time wiring. The system-under-test is built after the overlay, which is threaded into the builder's
overridingBeanStore(...)setter. Universal: every bean type is eligible for replacement, including ones the framework would otherwise pin into a per-op memoizer at boot. - Mode OVERLAY — push/pop overlays on a long-lived SUT (typically a
Microservicebooted once in@BeforeAll), applied and removed per test via@TestBean(mode = Mode.OVERLAY).
The overridingBeanStore(BeanStore) setter is available on every builder implementing BeanStoreOverridable<B>: MockRestClient.Builder, Microservice.Builder, SerializerSet.Builder, ParserSet.Builder, and EncoderSet.Builder.
Reference
@TestBean attributes
| Attribute | Default | Description |
|---|---|---|
name | "" | Bean qualifier name; empty means unnamed. |
type | Object.class | Bean type to register under. When left as Object.class the field's declared type (or the method's return type) is used. |
scope | Scope.METHOD | Scope.METHOD (fresh overlay per test method) or Scope.CLASS (shared overlay for the whole class; only valid on static members). |
mode | Mode.INJECT | Mode.INJECT or Mode.OVERLAY (see above). Mixing both modes within one scope throws IllegalStateException. |
@TestBean may be placed on fields or on methods (the method is invoked to supply the bean). Method-scope overlays are
stacked on top of the class-scope overlay, so a method-scope bean takes precedence over a class-scope bean of the same type.
Registering the extension
// Declarative
@ExtendWith(JuneauBeanStoreExtension.class)
class MyTest { ... }
// Programmatic, when you need the extension instance
class MyTest {
@RegisterExtension
static JuneauBeanStoreExtension ext = JuneauBeanStoreExtension.create();
}
JuneauBeanStoreExtension
implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback and ParameterResolver.
| Method | Description |
|---|---|
create() | Static factory for @RegisterExtension. |
attach(WritableBeanStore) / detach() | Attach the overlay to (or detach it from) a long-lived store, as used by Mode OVERLAY. |
getAttachedStore() | The attached store, as an Optional. |
getStore() | The active overlay for the current test method or class. |
getStore(Scope) | The overlay for the given scope, as an Optional<TestBeanStore>. |
discoverOverrides(Object) | Static; scans a test instance (and its hierarchy) for @TestBean members and returns the overrides. |
TestBeanStore
TestBeanStore extends BasicBeanStore
and has no JUnit dependency. It can be created with new TestBeanStore() or new TestBeanStore(BeanStore parent)
and can be declared as a test-method parameter to receive the current overlay.
| Method | Description |
|---|---|
override(Class<T>, T) | Register an unnamed override. |
override(Class<T>, T, String) | Register a named override. |
override(Class<T>, Supplier<T>) | Register a lazily supplied override. |
override(Class<T>, Supplier<T>, String) | Register a lazily supplied, named override. |
REST-focused deep dive
For a full walkthrough of @TestBean with MockRestClient — named-bean qualifiers, explicit-type overrides, per-test vs. per-class scope, and the Mode-OVERLAY safety inventory — see Test-time Bean Injection.