@TestBean
Replace Mocks With Real Implementations

Auto-mocking gets the container started. @TestBean lets you swap specific mocks for hand-crafted replacements — per test class, no @Priority, no global side effects.

When Mocks Aren't Enough

Auto-mocking gets the container started. But sometimes a Mockito mock isn't what you need — you want a real implementation that records calls, returns computed values, or validates inputs.

CDI has @Alternative for exactly this. With @Priority, they're globally enabled — which works fine and the addon doesn't interfere with that. But a globally enabled alternative affects every test on the classpath. Sometimes you need different replacements for different tests.

The Solution: @TestBean

@TestBean activates @Alternative beans per test class, without @Priority. The extension enables them programmatically and vetoes unselected alternatives to prevent conflicts. Existing Other alternatives — whether enabled via @Priority or beans.xml — continue to work normally as long as their bean types don't overlap with a @TestBean replacement. The extension respects @Typed on both sides when checking for type clashes.

  1. Create your replacement as a normal CDI bean with @Alternative — define your own scope, qualifiers, and logic. Don't add @Priority.
    @Alternative
    @ApplicationScoped
    public class CustomGreeting implements Greeting {
    
        @Override
        public String greet(String name) {
            return "Hello, " + name + "!";
        }
    }
  2. Annotate your test class with @EnableTestBeans + @TestBean to activate it. The annotation is repeatable — use multiple @TestBean when you need a few replacements. For larger setups, bundle them into composable meta-annotations.
    @EnableTestBeans
    @TestBean(bean = CustomGreeting.class)
    class GreetingTest {
        // Greeting injection points now use CustomGreeting
        // Everything else is still auto-mocked
    }
  3. Activate multiple replacements@TestBean is repeatable:
    @EnableTestBeans
    @TestBean(bean = CustomGreeting.class)
    @TestBean(bean = CustomNotificationSender.class)
    class FullIntegrationTest {
        // Both alternatives active, rest auto-mocked
    }
  4. Or use an inline @TestBean field — define and stub a Mockito mock right in the test class:
    @EnableTestBeans
    class GreetingTest {
    
        @TestBean
        private static Greeting greeting = Mockito.mock(Greeting.class);
    
        @Inject
        GreetingConsumer consumer;
    
        @Test
        void stubbedMockIsInjected() {
            Mockito.when(greeting.greet("world")).thenReturn("Stubbed!");
    
            assertEquals("Stubbed!", consumer.getGreeting().greet("world"));
            assertNull(consumer.getGreeting().greet("other"));  // unstubbed → null
        }
    }

    No separate class, no @Alternative, no @ApplicationScoped. The static field holds a pre-configured Mockito mock that becomes a CDI bean. Stubbing and verification work exactly as you'd expect.

For producer beans with @Produces methods, composable meta-annotations, whitelist mode, and more, see Advanced Features.