Skip to content

Commit ba6fe60

Browse files
committed
Merge branch '2.1.x'
Closes gh-17948
2 parents 2d2e3b3 + 52050c1 commit ba6fe60

File tree

2 files changed

+127
-3
lines changed

2 files changed

+127
-3
lines changed

spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Set;
2828
import java.util.TreeSet;
2929

30+
import org.springframework.aop.scope.ScopedObject;
3031
import org.springframework.aop.scope.ScopedProxyUtils;
3132
import org.springframework.beans.BeansException;
3233
import org.springframework.beans.PropertyValues;
@@ -357,6 +358,9 @@ private void inject(Field field, Object target, String beanName) {
357358
Assert.state(ReflectionUtils.getField(field, target) == null,
358359
() -> "The field " + field + " cannot have an existing value");
359360
Object bean = this.beanFactory.getBean(beanName, field.getType());
361+
if (bean instanceof ScopedObject) {
362+
bean = ((ScopedObject) bean).getTargetObject();
363+
}
360364
ReflectionUtils.setField(field, target, bean);
361365
}
362366
catch (Throwable ex) {
@@ -442,15 +446,22 @@ public int getOrder() {
442446

443447
@Override
444448
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
445-
return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName);
449+
return this.mockitoPostProcessor.createSpyIfNecessary(bean, getOriginalBeanNameIfScopedTarget(beanName));
446450
}
447451

448452
@Override
449453
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
450-
if (bean instanceof FactoryBean) {
454+
if (bean instanceof FactoryBean || bean instanceof ScopedObject) {
451455
return bean;
452456
}
453-
return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName);
457+
return this.mockitoPostProcessor.createSpyIfNecessary(bean, getOriginalBeanNameIfScopedTarget(beanName));
458+
}
459+
460+
private String getOriginalBeanNameIfScopedTarget(String beanName) {
461+
if (ScopedProxyUtils.isScopedTarget(beanName)) {
462+
return beanName.substring("scopedTarget.".length());
463+
}
464+
return beanName;
454465
}
455466

456467
static void register(BeanDefinitionRegistry registry) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.test.mock.mockito;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
22+
import org.springframework.beans.factory.ObjectFactory;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.beans.factory.config.CustomScopeConfigurer;
25+
import org.springframework.boot.test.mock.mockito.SpyBeanOnTestFieldForExistingScopedBeanIntegrationTests.SpyBeanOnTestFieldForExistingScopedBeanConfig;
26+
import org.springframework.boot.test.mock.mockito.example.ExampleService;
27+
import org.springframework.boot.test.mock.mockito.example.ExampleServiceCaller;
28+
import org.springframework.boot.test.mock.mockito.example.SimpleExampleService;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.context.annotation.Import;
32+
import org.springframework.context.annotation.Scope;
33+
import org.springframework.context.annotation.ScopedProxyMode;
34+
import org.springframework.test.context.ContextConfiguration;
35+
import org.springframework.test.context.junit.jupiter.SpringExtension;
36+
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.mockito.Mockito.verify;
39+
40+
/**
41+
* Test {@link SpyBean @SpyBean} on a test class field can be used to replace existing
42+
* scoped beans.
43+
*
44+
* @author Andy Wilkinson
45+
*/
46+
@ExtendWith(SpringExtension.class)
47+
@ContextConfiguration(classes = SpyBeanOnTestFieldForExistingScopedBeanConfig.class)
48+
public class SpyBeanOnTestFieldForExistingScopedBeanIntegrationTests {
49+
50+
@SpyBean
51+
private ExampleService exampleService;
52+
53+
@Autowired
54+
private ExampleServiceCaller caller;
55+
56+
@Test
57+
void testSpying() {
58+
assertThat(this.caller.sayGreeting()).isEqualTo("I say simple");
59+
verify(this.exampleService).greeting();
60+
}
61+
62+
@Configuration(proxyBeanMethods = false)
63+
@Import({ ExampleServiceCaller.class })
64+
static class SpyBeanOnTestFieldForExistingScopedBeanConfig {
65+
66+
@Bean
67+
@Scope(scopeName = "custom", proxyMode = ScopedProxyMode.TARGET_CLASS)
68+
SimpleExampleService simpleExampleService() {
69+
return new SimpleExampleService();
70+
}
71+
72+
@Bean
73+
static CustomScopeConfigurer customScopeConfigurer() {
74+
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
75+
configurer.addScope("custom", new org.springframework.beans.factory.config.Scope() {
76+
77+
private Object bean;
78+
79+
@Override
80+
public Object resolveContextualObject(String key) {
81+
throw new UnsupportedOperationException();
82+
}
83+
84+
@Override
85+
public Object remove(String name) {
86+
throw new UnsupportedOperationException();
87+
}
88+
89+
@Override
90+
public void registerDestructionCallback(String name, Runnable callback) {
91+
throw new UnsupportedOperationException();
92+
}
93+
94+
@Override
95+
public String getConversationId() {
96+
throw new UnsupportedOperationException();
97+
}
98+
99+
@Override
100+
public Object get(String name, ObjectFactory<?> objectFactory) {
101+
if (this.bean == null) {
102+
this.bean = objectFactory.getObject();
103+
}
104+
return this.bean;
105+
}
106+
107+
});
108+
return configurer;
109+
}
110+
111+
}
112+
113+
}

0 commit comments

Comments
 (0)