Class BeanContextBuilder


  • public class BeanContextBuilder
    extends Object
    Build a bean context with options for shutdown hook and supplying test doubles.

    We would choose to use BeanContextBuilder in test code (for component testing) as it gives us the ability to inject test doubles, mocks, spy's etc.

    
    
       @Test
       public void someComponentTest() {
    
         MyRedisApi mockRedis = mock(MyRedisApi.class);
         MyDbApi mockDatabase = mock(MyDbApi.class);
    
         try (BeanContext context = new BeanContextBuilder()
           .withBeans(mockRedis, mockDatabase)
           .build()) {
    
           // built with test doubles injected ...
           CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
           coffeeMaker.makeIt();
    
           assertThat(...
         }
       }
    
     
    • Constructor Detail

      • BeanContextBuilder

        public BeanContextBuilder()
        Create a BeanContextBuilder to ultimately load and return a new BeanContext.
        
        
           try (BeanContext context = new BeanContextBuilder()
             .build()) {
        
             String makeIt = context.getBean(CoffeeMaker.class).makeIt();
           }
         
    • Method Detail

      • withNoShutdownHook

        public BeanContextBuilder withNoShutdownHook()
        Boot the bean context without registering a shutdown hook.

        The expectation is that the BeanContextBuilder is closed via code or via using try with resources.

        
        
           // automatically closed via try with resources
        
           try (BeanContext context = new BeanContextBuilder()
             .withNoShutdownHook()
             .build()) {
        
             String makeIt = context.getBean(CoffeeMaker.class).makeIt();
           }
        
         
        Returns:
        This BeanContextBuilder
      • withModules

        public BeanContextBuilder withModules​(String... modules)
        Specify the modules to include in dependency injection.

        This is effectively a "whitelist" of modules names to include in the injection excluding any other modules that might otherwise exist in the classpath.

        We typically want to use this in component testing where we wish to exclude any other modules that exist on the classpath.

        
        
           @Test
           public void someComponentTest() {
        
             EmailServiceApi mockEmailService = mock(EmailServiceApi.class);
        
             try (BeanContext context = new BeanContextBuilder()
               .withBeans(mockEmailService)
               .withModules("coffee")
               .withIgnoreMissingModuleDependencies()
               .build()) {
        
               // built with test doubles injected ...
               CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
               coffeeMaker.makeIt();
        
               assertThat(...
             }
           }
        
         
        Parameters:
        modules - The names of modules that we want to include in dependency injection.
        Returns:
        This BeanContextBuilder
      • withIgnoreMissingModuleDependencies

        public BeanContextBuilder withIgnoreMissingModuleDependencies()
        Set this when building a BeanContext (typically for testing) and supplied beans replace module dependencies. This means we don't need the usual module dependencies as supplied beans are used instead.
      • withBeans

        public BeanContextBuilder withBeans​(Object... beans)
        Supply a bean to the context that will be used instead of any similar bean in the context.

        This is typically expected to be used in tests and the bean supplied is typically a test double or mock.

        
        
           Pump pump = mock(Pump.class);
           Grinder grinder = mock(Grinder.class);
        
           try (BeanContext context = new BeanContextBuilder()
             .withBeans(pump, grinder)
             .build()) {
        
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             Pump pump1 = context.getBean(Pump.class);
             Grinder grinder1 = context.getBean(Grinder.class);
        
             assertThat(pump1).isSameAs(pump);
             assertThat(grinder1).isSameAs(grinder);
        
             verify(pump).pumpWater();
             verify(grinder).grindBeans();
           }
        
         
        Parameters:
        beans - The bean used when injecting a dependency for this bean or the interface(s) it implements
        Returns:
        This BeanContextBuilder
      • withBean

        public <D> BeanContextBuilder withBean​(Class<D> type,
                                               D bean)
        Add a supplied bean instance with the given injection type.

        This is typically a test double often created by Mockito or similar.

        
        
           try (BeanContext context = new BeanContextBuilder()
             .withBean(Pump.class, mock)
             .build()) {
        
             Pump pump = context.getBean(Pump.class);
             assertThat(pump).isSameAs(mock);
        
             // act
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             verify(pump).pumpSteam();
             verify(pump).pumpWater();
           }
        
         
        Parameters:
        type - The dependency injection type this bean is target for
        bean - The supplied bean instance to use (typically a test mock)
      • withMock

        public BeanContextBuilder withMock​(Class<?> type)
        Use a mockito mock when injecting this bean type.
        
        
           try (BeanContext context = new BeanContextBuilder()
             .withMock(Pump.class)
             .withMock(Grinder.class, grinder -> {
               // setup the mock
               when(grinder.grindBeans()).thenReturn("stub response");
             })
             .build()) {
        
        
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             // this is a mockito mock
             Grinder grinder = context.getBean(Grinder.class);
             verify(grinder).grindBeans();
           }
        
         
      • withMock

        public <D> BeanContextBuilder withMock​(Class<D> type,
                                               Consumer<D> consumer)
        Use a mockito mock when injecting this bean type additionally running setup on the mock instance.
        
        
           try (BeanContext context = new BeanContextBuilder()
             .withMock(Pump.class)
             .withMock(Grinder.class, grinder -> {
        
               // setup the mock
               when(grinder.grindBeans()).thenReturn("stub response");
             })
             .build()) {
        
        
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             // this is a mockito mock
             Grinder grinder = context.getBean(Grinder.class);
             verify(grinder).grindBeans();
           }
        
         
      • withSpy

        public BeanContextBuilder withSpy​(Class<?> type)
        Use a mockito spy when injecting this bean type.
        
        
           try (BeanContext context = new BeanContextBuilder()
             .withSpy(Pump.class)
             .build()) {
        
             // setup spy here ...
             Pump pump = context.getBean(Pump.class);
             doNothing().when(pump).pumpSteam();
        
             // act
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             verify(pump).pumpWater();
             verify(pump).pumpSteam();
           }
        
         
      • withSpy

        public <D> BeanContextBuilder withSpy​(Class<D> type,
                                              Consumer<D> consumer)
        Use a mockito spy when injecting this bean type additionally running setup on the spy instance.
        
        
           try (BeanContext context = new BeanContextBuilder()
             .withSpy(Pump.class, pump -> {
               // setup the spy
               doNothing().when(pump).pumpWater();
             })
             .build()) {
        
             // or setup here ...
             Pump pump = context.getBean(Pump.class);
             doNothing().when(pump).pumpSteam();
        
             // act
             CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
             coffeeMaker.makeIt();
        
             verify(pump).pumpWater();
             verify(pump).pumpSteam();
           }
        
         
      • build

        public BeanContext build()
        Build and return the bean context.
        Returns:
        The BeanContext