-
Notifications
You must be signed in to change notification settings - Fork 40.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@SpyBean and @MockBean fails on verify, after spring-tx is added to classpath #5837
Comments
The |
I have a similar problem with caching. Let's say I have If
If I change my vanilla
|
Mockito is getting confused by the two layers of proxying. The spy bean has created one proxy and persistence exception translation has created another. The reproduction includes this test: @Test
public void test() {
service.doSomething(99);
Mockito.verify(repository).save(99);
Mockito.verifyNoMoreInteractions(repository);
} Things go wrong when |
I had thought that one way to fix this would be to ensure that the proxy for the spy is created last. However, this isn't possible as Spring Framework's |
An alternative is to "unwrap" the proxy so that Mockito's proxy is injected into the test rather than Spring Framework's: diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java
index e76208e..2833bfc 100644
--- a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java
+++ b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoPostProcessor.java
@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
+import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
@@ -308,6 +309,9 @@ 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 (bean instanceof Advised) {
+ bean = ((Advised) bean).getTargetSource().getTarget();
+ }
ReflectionUtils.setField(field, target, bean);
}
catch (Throwable ex) { I'm unconvinced, though. Any calls that the test makes to the spied class will miss out on any functionality that was added by Spring Framework's proxy. |
@robersonccgomes Thanks for the issue report and for the sample application, it was very helpful for tracking down the cause. |
I'm glad I could help @philwebb. |
@philwebb our sample app now works as expected with that fix. Thanks! |
Post-processing of mocked beans causes a number of problems: - The mock may be proxied for asynchronous processing which can cause problems when configuring expectations on a mock (spring-projectsgh-6573) - The mock may be proxied so that its return values can be cached or so that its methods can be transactional. This causes problems with verification of the expected calls to a mock (spring-projectsgh-6573, spring-projectsgh-5837) - If the mock is created from a class that uses field injection, the container will attempt to inject values into its fields. This causes problems if the mock is being created to avoid the use of one of those dependencies (spring-projectsgh-6663) - Proxying a mocked bean can lead to a JDK proxy being created (if proxyTargetClass=false) as the mock implements a Mockito interface. This can then cause injection failures as the types don’t match (spring-projectsgh-6405, spring-projectsgh-6665) All of these problems can be avoided if a mocked bean is not post-processed. Avoiding post-processing prevents proxies from being created and autowiring from being performed. This commit avoids post-processing by registering mocked beans as singletons rather than via a bean definition.
Post-processing of mocked beans causes a number of problems: - The mock may be proxied for asynchronous processing which can cause problems when configuring expectations on a mock (gh-6573) - The mock may be proxied so that its return values can be cached or so that its methods can be transactional. This causes problems with verification of the expected calls to a mock (gh-6573, gh-5837) - If the mock is created from a class that uses field injection, the container will attempt to inject values into its fields. This causes problems if the mock is being created to avoid the use of one of those dependencies (gh-6663) - Proxying a mocked bean can lead to a JDK proxy being created (if proxyTargetClass=false) as the mock implements a Mockito interface. This can then cause injection failures as the types don’t match (gh-6405, gh-6665) All of these problems can be avoided if a mocked bean is not post-processed. Avoiding post-processing prevents proxies from being created and autowiring from being performed. This commit avoids post-processing by registering mocked beans as singletons as well as via a bean definition. The latter is still used by the context for type matching purposes. Closes gh-6573, gh-6663, gh-6664
I'm using
spring-boot 1.4.0.M2
and I having some trouble using@SpyBean
and@MockBean
in my tests.Both annotations were working fine, but after I added
spring-boot-starter-jdbc
to my project, my tests started to fail on spy/mock verifications with:I removed
spring-boot-starter-jdbc
dependency and addedspring-tx
and the error still there.I've created a project reproducing the issue: https://github.com/robersonccgomes/spring-boot-spybean-bug
The text was updated successfully, but these errors were encountered: