Advanced @TestBean
Producer Beans, Whitelist Mode, Meta-Annotations

Beyond basic @TestBean — features for complex test setups and reusable configurations.

This post builds on the auto-mocking and @TestBean basics features. Make sure you're familiar with those first.

1. Producer Bean Replacements

When a single @Alternative class should provide multiple bean types, use beanProducer to activate a class with @Produces methods:

@Alternative
@ApplicationScoped
public class TestProducers {

    @Produces
    public AuditService audit() {
        return action -> { /* no-op */ };
    }

    @Produces
    public MetricsService metrics() {
        return Mockito.mock(MetricsService.class);
    }
}

@EnableTestBeans
@TestBean(beanProducer = TestProducers.class)
class MyTest {
    // AuditService and MetricsService from TestProducers
    // Everything else auto-mocked
}

bean and beanProducer can be combined:

@EnableTestBeans
@TestBean(bean = CustomGreeting.class)
@TestBean(beanProducer = TestProducers.class)
class MyTest { ... }

2. Whitelist Mode

limitToTestBeans = true vetoes all application beans except those explicitly declared via @TestBean. CDI internals (Weld, OWB, DeltaSpike) are preserved. No auto-mocking occurs.

@EnableTestBeans(limitToTestBeans = true)
@TestBean(bean = CustomGreeting.class)
class MyTest {
    // Only CustomGreeting is active.
    // All other application beans are vetoed.
    // No Mockito mocks are created.
}

This is useful for true unit tests where you want complete control over which beans exist. If a @TestBean references a class that has no @TestBean on this test, the injection point is unsatisfied — the container tells you exactly what's missing.

3. Composable Meta-Annotations

Bundle @TestBean declarations into reusable annotations. Meta-annotations can nest to any depth, and duplicate bean references across levels are deduplicated automatically.

Level 1: single concern

@TestBean(bean = CustomGreeting.class)
@Retention(RUNTIME)
@Target({TYPE, ANNOTATION_TYPE})
public @interface GreetingMocks {}

Level 2: compose level-1 annotations

@GreetingMocks
@NotificationMocks
@Retention(RUNTIME)
@Target({TYPE, ANNOTATION_TYPE})
public @interface StandardMocks {}

Level 3: compose level-2 + add more

@StandardMocks
@TestBean(beanProducer = AuditProducers.class)
@TestBean(bean = CustomGreeting.class)  // redundant — already in @GreetingMocks
@Retention(RUNTIME)
@Target({TYPE, ANNOTATION_TYPE})
public @interface FullTestSetup {}

Usage

@EnableTestBeans
@FullTestSetup
class MyTest {
    // Gets: CustomGreeting + CustomNotificationSender + AuditProducers
    // Duplicate CustomGreeting is silently deduplicated
}
Deduplication is automatic. The same bean class can appear in multiple @TestBean annotations across any number of meta-annotation levels. The extension collects them into a Set — duplicates are a no-op, not an error.

Feature Summary

FeatureAnnotationDefault
Activate @Alternative producer bean @TestBean(beanProducer = ...)
Whitelist mode (veto all others) @EnableTestBeans(limitToTestBeans = true) Off
Composable meta-annotations @TestBean on custom annotations Recursive, deduplicated
Manual container management @EnableTestBeans(manageContainer = false) Off (auto-managed by default)
Disable test class injection @EnableTestBeans(addTestClass = false) Off (injected by default)