在Spring集成测试期间刷新/重建特定的bean

时间:2018-11-08 17:25:54

标签: java spring spring-boot junit integration-testing

我们现有的Spring Boot集成设置使用@DirtiesContext在不同的测试方法之间重建整个bean池。

这相当慢,因此我们开始使用可以在内部“刷新”或拆卸/重建 的bean,而无需重新创建实例。

问题是仅某些bean支持此功能。如果我们控制UsersBean,则可以实现UsersBean.refresh()方法并在@After方法中调用它。

但是,如果我们有不支持刷新或无法控制的现有bean /类,我们如何有条件有条件地指出某些豆需要在特定测试后进行脏污/重建?

或更简洁地说:在测试方法结束时,是否有一种方法可以将豆池的小节标记为脏的,以便进行重建?

1 个答案:

答案 0 :(得分:3)

至少在Spring Boot环境中,这似乎是可行的。 ApplicationContext实现有一个GenericApplicationContext,它具有removeBeanDefinition()的功能,然后可以通过registerBeanDefinition()重新注册。

这甚至会级联完成以删除包含对要删除的bean的引用的bean(可以在DefaultSingletonBeanRegistry.destroyBean()中看到其实现)。

例如,如果Bean1引用了Bean2

@Component
public class Bean1 {

}

@Component
public class Bean2 {
    @Autowired
    public Bean1 bean1;
}

然后测试可以从上下文中删除bean1,并看到bean2也被替换了:

@RunWith(SpringRunner.class)
public class BeanRemovalTest implements ApplicationContextAware {
    @Autowired
    private Bean1 bean1;

    @Autowired
    private Bean2 bean2;

    private ApplicationContext applicationContext;

    @Test
    public void test1() throws Exception {
        System.out.println("test1():");
        System.out.println("  bean1=" + bean1);
        System.out.println("  bean2.bean1=" + bean2.bean1);

        resetBean("bean1");
    }

    @Test
    public void test2() throws Exception {
        System.out.println("test2():");
        System.out.println("  bean1=" + bean1);
        System.out.println("  bean2.bean1=" + bean2.bean1);
    }

    private void resetBean(String beanName) {
        GenericApplicationContext genericApplicationContext = (GenericApplicationContext) applicationContext;
        BeanDefinition bd = genericApplicationContext
                .getBeanDefinition(beanName);
        genericApplicationContext.removeBeanDefinition("bean1");
        genericApplicationContext.registerBeanDefinition("bean1", bd);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }
}

这显示两个bean实例都将被替换:

test1():
  bean1=hello.so.Bean1@61d6015a
  bean2.bean1=hello.so.Bean1@61d6015a

test2():
  bean1=hello.so.Bean1@2e570ded
  bean2.bean1=hello.so.Bean1@2e570ded

(如果将resetBean("bean1")注释掉,则两次都是同一实例)。

在某些方面无法解决-例如如果另一个bean保留了从ApplicationContext.getBean()获得的引用。