Обновлять / перестраивать определенные bean-компоненты во время тестирования интеграции Spring - PullRequest
0 голосов
/ 08 ноября 2018

Наша существующая настройка интеграции Spring Boot использовала @DirtiesContext для перестройки всего пула компонентов между различными методами тестирования.

Это было довольно медленно, и поэтому мы начали работать с bean-компонентами, которые можно было "обновить" или разрушить / перестроить внутри без повторного создания экземпляра.

Проблема в том, что только некоторые бины поддерживают это. Если мы контролируем UsersBean, мы можем реализовать метод UsersBean.refresh() и вызвать его в нашем методе @After.

Но если у нас есть существующие бины / классы, которые не поддерживают обновление, или мы не контролируем, как мы можем условно указать, что определенные бины должны быть загрязнены / перестроены после определенного теста?

Или, более кратко: есть ли способ пометить как грязный подраздел вашего пула бобов для восстановления в конце метода тестирования?

1 Ответ

0 голосов
/ 25 января 2019

Похоже, это возможно, по крайней мере, в среде 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;
    }
}

Показывает замену обоих экземпляров бина:

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") закомментирован, то это один и тот же экземпляр оба раза).

Обязательно должны быть ребра, где это не сработает - например, если другой бин держит ссылку, полученную из ApplicationContext.getBean().

...