How to programmatically create a spring context?

Does anyone know if there is a way that I can programmatically create a bean context?

I want to be able to do something like:

ConfigurableApplicationContext c = new ConfigurableApplicationContext(); BeanDefinition bd = new BeanDefinition(); bd.setId("id"); bd.setClassName("classname"); bd.setProperty("propertyName", propertyValue"); ...etc... 

or it’s even better to embed a ready-made bean in the application context:

 c.addBean("beanId", beanObject); 

Or if I use annotations:

 c.setAnnotationAware(true); c.setAnnotationScanBasePackage("packagename"); 

or

 c.addAnnotatedSpringClass("classnamethatisannotated"); 

The rationale for this is that I want to override bean definitions for testing purposes. In my test, I create this new application context, configured with the code in the test (and not in xml), and then do it the test context of the application have the SUT application context as the parent.

I have not found any code in spring libraries that can do this. Has anyone built something like this? Is it possible to build something like this? I know that the previous approach is feasible, I am not 100% sure that the latter will work without any conditions.

+6
spring unit-testing
source share
5 answers

Try either:


JavaConfig Sample Code

 @Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } } 

BeanBuilder Sample Code

 def bb = new grails.spring.BeanBuilder() bb.beans { dataSource(BasicDataSource) { driverClassName = "org.hsqldb.jdbcDriver" url = "jdbc:hsqldb:mem:grailsDB" username = "sa" password = "" } sessionFactory(ConfigurableLocalSessionFactoryBean) { dataSource = dataSource hibernateProperties = [ "hibernate.hbm2ddl.auto":"create-drop", "hibernate.show_sql":true ] } } 

AtUnit Code Example

Unit test

 @RunWith(AtUnit.class) @Container(Container.Option.SPRING) @MockFramework(MockFramework.Option.EASYMOCK) public class ExampleSpringEasyMockTest { @Bean @Unit UserManagerImpl manager; @Bean("fred") User fred; @Bean("userDao") @Mock UserDao dao; @Bean("log") @Stub Logger log; @Test public void testGetUser() { expect(dao.load(1)).andReturn(fred); replay(dao); assertSame(fred, manager.getUser(1)); verify(dao); } } 

Context file (closed for test)

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="userManager" class="atunit.example.subjects.UserManagerImpl"> <constructor-arg ref="log"/> <property name="userDao" ref="userDao"/> </bean> <bean id="fred" class="atunit.example.subjects.User"> <property name="id" value="500"/> <property name="username" value="fred"/> </bean> </beans> 
+9
source share

Why don't you just use two different contexts? one for production, one for tests ... you go about it the hard way.

+4
source share

In Spring, you can override a bean definition as easily as making them appear again below in the file. We use this a lot for the very purpose that you have described; have a different bean definition for unit tests than for production.

This is the template we use for our test-context.xml

 <import resource="classpath:production-context.xml"> <bean id="overriddenBean" class="com.MyClass"> .... </bean> 

This means that a bean with id = overriddenBean will be connected to classes in your command loops if referenced. Letting you change the beans, you need to test instead of the ones you need for production code.

Hope this helps

+4
source share

Just add a bean factory mail processor that can manipulate / add any bean definition

  public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor { public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinition beanDefinition=... ((BeanDefinitionRegistry)beanFactory).registerBeanDefinition(name, beanDefinition); } } } 
+3
source share

There is a whole new way to do this - Spring Download

 import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @Configuration @ComponentScan @EnableAutoConfiguration public class Application implements CommandLineRunner { private static final Logger LOG = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void run(String... args) throws Exception { LOG.info("Hello world"); } } 
+1
source share

All Articles