Spring test context best practice

前端 未结 2 504
旧巷少年郎
旧巷少年郎 2021-02-04 11:20

I\'m trying to cover a huge Spring Boot application with integration tests. There are lots of Spring beans within the app. It takes a while to load the Spring context.

2条回答
  •  Happy的楠姐
    2021-02-04 12:04

    Another trick that you can use in your integration tests is to force all the beans in the context to be "lazy". This is really useful when running just one integration test, as you do not have to wait for the entire application context to be loaded and initialized. This can significantly improve the time it takes to run a single test.

    You may run into situations where beans are being implicitly created (Example: Spring IntegrationFlow). The flow is never directly injected into anything but your classes may have references to beans that the flow creates. In this case you either need to @Autowire your flow (to insure the implicit beans get created) or you can get creative with a BeanPostProcessor.

    I created the following post processor and you just have to add it to your testing spring context.

    public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        private Class[] exclusionList;
    
        public LazyInitBeanFactoryPostProcessor() {
        }
    
        public LazyInitBeanFactoryPostProcessor(Class[] exclusionList) {
            this.exclusionList = exclusionList;
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
            //Iterate over all bean, mark them as lazy if they are not in the exclusion list.
            for (String beanName : beanFactory.getBeanDefinitionNames()) {
                if (isLazy(beanName, beanFactory)) {
                    BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
                    definition.setLazyInit(true);
                }
            }
        }
    
        private boolean isLazy(String beanName, ConfigurableListableBeanFactory beanFactory) {
            if (exclusionList == null || exclusionList.length == 0) {
                return true;
            }
            for (Class clazz : exclusionList) {
                if (beanFactory.isTypeMatch(beanName,clazz)) {
                    return false;
                } 
            } 
            return true;        
        }
    }
    

    And to use it:

    @SpringBootTest(webEnvironment = WebEnvironment.NONE)
    public class MyTest {
    .
    .
    .
    @TestConfiguration
    protected static class TestConfiguration {
    
        @Bean
        public BeanFactoryPostProcessor lazyBeanPostProcessor() {
            return new LazyInitBeanFactoryPostProcessor();
        }
    }
    

    Or you extend it with exclusions (In this example, any bean that is assignable to a Spring Integration flow will NOT be marked as lazy:

    @TestConfiguration
    protected static class TestConfiguration {
        @Bean
        public BeanFactoryPostProcessor lazyBeanPostProcessor() {
            return new ExtendedTestLazyBeanFactoryPostProcessor();
        }
    
    
        static private class ExtendedTestLazyBeanFactoryPostProcessor extends LazyInitBeanFactoryPostProcessor {    
            public ServiceTestLazyBeanFactoryPostProcessor() {
                super(new Class[] {IntegrationFlow.class});
            }   
        }
    

提交回复
热议问题