How can I instantiate and programmatically register beans to Spring ApplicationContext from a test class?

27 Views Asked by At

I attempting to instantiate Spring boot applicationContext and dynamically register beans within a test class to so it can acts as the real main class client's behavior. But I run the code (sample below) somehow the bean I register gets lost when it reaches to ClassFromMainCode.isBean method.

Testing class

@SpringBootTest( 
   classes = { ClassFromMainCode.class },
   webEnvironment = Spring.WebEnvironment.NONE
)
@Configuration
@ContextConfiguration
public class SampleTestClass {
  private ConfigurableApplicationContext applicationContext;  

  @Test
  public void testCase1() {
          beanName = "abc";
          Class beanClass = String.class;
          registerSpringBean(beanName, beanClass);

          //returns False
          new ClassFromMainCode().isBean(beanName);

          //returns True
          this.applicationContext.containsBean(beanName);
  }  

  private void registerSpringBean(String beanName, Class<?> beanClass) {
          BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext;
          registry.registerBeanDefinition(beanName, new TestGenericBeanDefinition(beanClass));
          applicationContext.refresh();
  }  

  public SampleTestClass() {
          applicationContext = new AnnotationConfigApplicationContext();
  }
} 

Main class

@Component
public class ClassFromMainCode {

  @Autowired
  private ApplicationContext applicationContext;

  boolean isBean(String beanName) {
          return applicationContext.containsBean(beanName);
  }
}

I expected the new ClassFromMainCode().isBean(beanName); to return true instead of false. I am wondering how I can appropriately define Spring applicationContext and register beans in a way that is presevered to reach to main code?

1

There are 1 best solutions below

0
VHS On

You are having two different application contexts. (1) created by you in the constructor of the test class. You use this one in your test method to register a bean called "abc". (2) created by Spring as a result of your annotation @SpringBootTest on your test class. This context only contains beans declared in the classes specified in the classes property. You have only one class declared in that property ClassFromMainCode which doesn't contain any beans.

I expected the new ClassFromMainCode().isBean(beanName); to return true instead of false. I am wondering how I can appropriately define Spring applicationContext and register beans in a way that is presevered to reach to main code?

Fix

Instead of creating your own application context in the constructor, use the one created by Spring for you. Autowire it in your test class and use that one instead.

@SpringBootTest( 
   classes = { ClassFromMainCode.class },
   webEnvironment = Spring.WebEnvironment.NONE
)
@Configuration
@ContextConfiguration
public class SampleTestClass {

   @Autowired
   private ConfigurableApplicationContext applicationContext;
   ...
   ...
}

Delete the constructor.