Skip to content

Commit bc53fe0

Browse files
committed
Recommend mockito-inline for mocking and spying of CGLib proxies
This reverts commit 52050c1. See gh-17817 Closes gh-19020
1 parent 3e2b466 commit bc53fe0

File tree

3 files changed

+10
-130
lines changed

3 files changed

+10
-130
lines changed

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5801,6 +5801,11 @@ We recommend using a `@Bean` method to create and configure the mock in this sit
58015801
Additionally, you can use `@SpyBean` to wrap any existing bean with a Mockito `spy`.
58025802
See the {spring-boot-test-module-api}/mock/mockito/SpyBean.html[Javadoc] for full details.
58035803

5804+
NOTE: CGLib proxies, such as those created for scoped beans, declare the proxied methods as `final`.
5805+
This stops Mockito from functioning correctly as it cannot mock or spy on `final` methods in its default configuration.
5806+
If you want to mock or spy on such a bean, configure Mockito to use its inline mock maker by adding `org.mockito:mockito-inline` to your application's test dependencies.
5807+
This allows Mockito to mock and spy on `final` methods.
5808+
58045809
NOTE: While Spring's test framework caches application contexts between tests and reuses a context for tests sharing the same configuration, the use of `@MockBean` or `@SpyBean` influences the cache key, which will most likely increase the number of contexts.
58055810

58065811
TIP: If you are using `@SpyBean` to spy on a bean with `@Cacheable` methods that refer to parameters by name, your application must be compiled with `-parameters`.

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

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

30-
import org.springframework.aop.scope.ScopedObject;
3130
import org.springframework.aop.scope.ScopedProxyUtils;
3231
import org.springframework.beans.BeansException;
3332
import org.springframework.beans.PropertyValues;
@@ -360,9 +359,6 @@ private void inject(Field field, Object target, String beanName) {
360359
Assert.state(ReflectionUtils.getField(field, target) == null,
361360
() -> "The field " + field + " cannot have an existing value");
362361
Object bean = this.beanFactory.getBean(beanName, field.getType());
363-
if (bean instanceof ScopedObject) {
364-
bean = ((ScopedObject) bean).getTargetObject();
365-
}
366362
ReflectionUtils.setField(field, target, bean);
367363
}
368364
catch (Throwable ex) {
@@ -427,9 +423,8 @@ private static BeanDefinition getOrAddBeanDefinition(BeanDefinitionRegistry regi
427423
}
428424

429425
/**
430-
* {@link BeanPostProcessor} to handle {@link SpyBean @SpyBean} definitions.
431-
* Registered as a separate processor so that it can be ordered above AOP post
432-
* processors.
426+
* {@link BeanPostProcessor} to handle {@link SpyBean} definitions. Registered as a
427+
* separate processor so that it can be ordered above AOP post processors.
433428
*/
434429
static class SpyPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements PriorityOrdered {
435430

@@ -448,22 +443,15 @@ public int getOrder() {
448443

449444
@Override
450445
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
451-
return this.mockitoPostProcessor.createSpyIfNecessary(bean, getOriginalBeanNameIfScopedTarget(beanName));
446+
return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName);
452447
}
453448

454449
@Override
455450
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
456-
if (bean instanceof FactoryBean || bean instanceof ScopedObject) {
451+
if (bean instanceof FactoryBean) {
457452
return bean;
458453
}
459-
return this.mockitoPostProcessor.createSpyIfNecessary(bean, getOriginalBeanNameIfScopedTarget(beanName));
460-
}
461-
462-
private String getOriginalBeanNameIfScopedTarget(String beanName) {
463-
if (ScopedProxyUtils.isScopedTarget(beanName)) {
464-
return beanName.substring("scopedTarget.".length());
465-
}
466-
return beanName;
454+
return this.mockitoPostProcessor.createSpyIfNecessary(bean, beanName);
467455
}
468456

469457
public static void register(BeanDefinitionRegistry registry) {

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

Lines changed: 0 additions & 113 deletions
This file was deleted.

0 commit comments

Comments
 (0)