Filter scoped target proxy beans from Mockito
Update MockitoPostProcessor to filter bean names that match `ScopedProxyUtils.isScopedTarget` from the candidates list. Fixes gh-5724
This commit is contained in:
parent
682f20ebf7
commit
f0b6d346d7
|
|
@ -18,14 +18,18 @@ package org.springframework.boot.test.mock.mockito;
|
|||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
|
|
@ -208,8 +212,8 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
if (StringUtils.hasLength(mockDefinition.getName())) {
|
||||
return mockDefinition.getName();
|
||||
}
|
||||
String[] existingBeans = beanFactory
|
||||
.getBeanNamesForType(mockDefinition.getClassToMock());
|
||||
String[] existingBeans = getExistingBeans(beanFactory,
|
||||
mockDefinition.getClassToMock());
|
||||
if (ObjectUtils.isEmpty(existingBeans)) {
|
||||
return this.beanNameGenerator.generateBeanName(beanDefinition, registry);
|
||||
}
|
||||
|
|
@ -224,8 +228,8 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
|
||||
private void registerSpy(ConfigurableListableBeanFactory beanFactory,
|
||||
BeanDefinitionRegistry registry, SpyDefinition definition, Field field) {
|
||||
String[] existingBeans = beanFactory
|
||||
.getBeanNamesForType(definition.getClassToSpy());
|
||||
String[] existingBeans = getExistingBeans(beanFactory,
|
||||
definition.getClassToSpy());
|
||||
if (ObjectUtils.isEmpty(existingBeans)) {
|
||||
createSpy(registry, definition, field);
|
||||
}
|
||||
|
|
@ -234,6 +238,27 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
}
|
||||
}
|
||||
|
||||
private String[] getExistingBeans(ConfigurableListableBeanFactory beanFactory,
|
||||
Class<?> type) {
|
||||
List<String> beans = new ArrayList<String>(
|
||||
Arrays.asList(beanFactory.getBeanNamesForType(type)));
|
||||
for (Iterator<String> iterator = beans.iterator(); iterator.hasNext();) {
|
||||
if (isScopedTarget(iterator.next())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return beans.toArray(new String[beans.size()]);
|
||||
}
|
||||
|
||||
private boolean isScopedTarget(String beanName) {
|
||||
try {
|
||||
return ScopedProxyUtils.isScopedTarget(beanName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void createSpy(BeanDefinitionRegistry registry, SpyDefinition definition,
|
||||
Field field) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
|
|
@ -309,7 +334,7 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
Assert.state(ReflectionUtils.getField(field, target) == null,
|
||||
"The field " + field + " cannot have an existing value");
|
||||
Object bean = this.beanFactory.getBean(beanName, field.getType());
|
||||
if (definition.isProxyTargetAware() && AopUtils.isAopProxy(bean)) {
|
||||
if (definition.isProxyTargetAware() && isAopProxy(bean)) {
|
||||
MockitoAopProxyTargetInterceptor.applyTo(bean);
|
||||
}
|
||||
ReflectionUtils.setField(field, target, bean);
|
||||
|
|
@ -319,6 +344,15 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isAopProxy(Object object) {
|
||||
try {
|
||||
return AopUtils.isAopProxy(object);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE - 10;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2012-2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.mock.mockito;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleService;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleServiceCaller;
|
||||
import org.springframework.boot.test.mock.mockito.example.FailingExampleService;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Test {@link MockBean} when used in combination with scoped proxy targets.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see <a href="https://github.com/spring-projects/spring-boot/issues/5724">gh-5724</a>
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class MockBeanOnScopedProxyTests {
|
||||
|
||||
@MockBean
|
||||
private ExampleService exampleService;
|
||||
|
||||
@Autowired
|
||||
private ExampleServiceCaller caller;
|
||||
|
||||
@Test
|
||||
public void testMocking() throws Exception {
|
||||
given(this.caller.getService().greeting()).willReturn("Boot");
|
||||
assertThat(this.caller.sayGreeting()).isEqualTo("I say Boot");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ ExampleServiceCaller.class })
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public ExampleService exampleService() {
|
||||
return new FailingExampleService();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue