Prevent early initialization in MockitoPostProcessor

Fixes gh-20665
This commit is contained in:
Madhura Bhave 2020-04-22 14:35:50 -07:00
parent 102729b5e1
commit b9c2b7b257
2 changed files with 60 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -247,9 +247,9 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
}
private Set<String> getExistingBeans(ConfigurableListableBeanFactory beanFactory, ResolvableType type) {
Set<String> beans = new LinkedHashSet<>(Arrays.asList(beanFactory.getBeanNamesForType(type)));
Set<String> beans = new LinkedHashSet<>(Arrays.asList(beanFactory.getBeanNamesForType(type, true, false)));
String typeName = type.resolve(Object.class).getName();
for (String beanName : beanFactory.getBeanNamesForType(FactoryBean.class)) {
for (String beanName : beanFactory.getBeanNamesForType(FactoryBean.class, true, false)) {
beanName = BeanFactoryUtils.transformedBeanName(beanName);
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (typeName.equals(beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE))) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,18 @@
package org.springframework.boot.test.mock.mockito;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.test.mock.mockito.example.ExampleService;
import org.springframework.boot.test.mock.mockito.example.FailingExampleService;
@ -29,6 +36,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.Assert;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@ -39,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Phillip Webb
* @author Andy Wilkinson
* @author Andreas Neiser
* @author Madhura Bhave
*/
class MockitoPostProcessorTests {
@ -123,6 +134,16 @@ class MockitoPostProcessorTests {
assertThat(Mockito.mockingDetails(context.getBean("exampleQualified", ExampleService.class)).isSpy()).isTrue();
}
@Test
void postProcessorShouldNotTriggerEarlyInitialization() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(FactoryBeanRegisteringPostProcessor.class);
MockitoPostProcessor.register(context);
context.register(TestBeanFactoryPostProcessor.class);
context.register(EagerInitBean.class);
context.refresh();
}
@Configuration(proxyBeanMethods = false)
@MockBean(SomeInterface.class)
static class MockedFactoryBean {
@ -258,6 +279,14 @@ class MockitoPostProcessorTests {
}
@Configuration(proxyBeanMethods = false)
static class EagerInitBean {
@MockBean
private ExampleService service;
}
static class TestFactoryBean implements FactoryBean<Object> {
@Override
@ -275,6 +304,33 @@ class MockitoPostProcessorTests {
return true;
}
};
static class FactoryBeanRegisteringPostProcessor implements BeanFactoryPostProcessor, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestFactoryBean.class);
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition("test", beanDefinition);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
static class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
@SuppressWarnings("unchecked")
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, BeanWrapper> cache = (Map<String, BeanWrapper>) ReflectionTestUtils.getField(beanFactory,
"factoryBeanInstanceCache");
Assert.isTrue(cache.isEmpty(), "Early initialization of factory bean triggered.");
}
}
interface SomeInterface {