-
Notifications
You must be signed in to change notification settings - Fork 38.3k
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
Mockito mock falsely initialized as CGLIB proxy with AspectJ aspect #33113
Comments
Thanks for raising this, I can imagine a side effect in a Mockito scenario indeed. Am I understanding correctly that you got an AspectJ aspect configured as a bean and applied with compile-time weaving, and the Spring AOP auto-proxying accidentally picked it up for building a CGLIB proxy - and that latter part got fixed by #32970? So what remains is an accidental extra call for a Mockito mock that's set up as a Spring bean as well? Is there still a CGLIB proxy being built for that Mockito mock where you do not intend to have a CGLIB proxy as all? I assume that Mockito mock is of the same type as your regular target bean and therefore matched by auto-proxying as well, and not excluded by #32970 either since the Mockito mock class itself is not compiled by What is your test actually trying to assert there? Is it expecting any interactions between the aspect and the Mockito mock at all? |
Is your Mockito mock effectively extending the class that the aspect actually targets? Is its superclass compiled by |
Trying various Mockito scenarios, your I've tried that with a patch in |
The project configuration is all over the place, so I have a hard time evaluating this. I might outline what I find in more detail later. We definitely have compile time weaving set up in the project. That much I know.
There is a LoggingAspect where I set a breakpoint in the log Method to see where it is called from in the stack:
This is a rough outline of a test that fails:
Here the inOrder.verify() call indirectly expects only one call to log and with 6.1.8 there were 3 calls to log instead of one, now there are 2 calls:
I think up to 6.1.8 there was only one call from MyAdminServiceAspectDelegate, none from a Mockito mock. So I think what you are writing is basically correct!?
I think this is the case and debugging confirmed it - not sure if I understand the nuances here, though.
This is where I have a hard time wrapping my head around the configuration. I'm still looking for the code that defines how the Mockito mock instance is defined. But that seems to make sense. If LTW for example has changed in 6.1.8 and is not covered by the fix, something like that might explain things. |
Purely intuitively speaking I think checking for ajc markers in the superclass is worth a shot and nothing else comes to mind immediately that needs to be taken into consideration. It is worth a shot, I think. |
Alright, thanks for the feedback! I've pushed the superclass check to 6.1.x, this will be available in the upcoming |
Thank you for looking into this! I have tested it, but it didn't seem to make a difference. I imported the 6.1.11-SNAPSHOT version of the spring-framework-bom to override the spring-boot 3.2.7 bom versions and checked the Maven tree to verify that the expected spring libraries have been resolved properly. |
Hmm, could you try to step through Another possible explanation is that your Mockito mock is somehow running with the pre-compiled AspectJ aspect in the application context but not with compile-time weaving applied to the corresponding application classes. We would have simply ignored the ajc-compiled aspect in that case before, whereas we are actually considering the aspect for proxying now if the target classes are not weaved. Your test setup might have accidentally relied on this before. In order to arrive at consistent behavior in that case, you'd have to run against the |
I tried to step through using the debugger. There are no Fields that start with I might have to look into the suggested changes with a colleague next week. With my current understanding of the configuration I wouldn't know where to start changing things ^^. Thanks you for the pointers and the time you put into this. |
That makes sense, Now I'm wondering why the aspect is present in your test configuration to begin with... when it is effectively not expected to apply to the mocked |
At this point, the superclass check seems worth fixing and backporting in any case since it covers superclass-derived mocks where the superclass has the aspect behavior weaved in already. For scenarios where the target bean does not have the aspect behavior yet, it arguably is correct to apply it via CGLIB then. The general goal is to consistently apply aspects but prevent double execution of aspects against the same target bean, and as far as I understand the scenario above, that is the case here. The test assertions should expect the aspect behavior to be applied to the Mockito mock as well: for every matching target object, but just once per target object. |
Closing this issue based on the reasoning above, to be reopened if any further steps on our side are being identified before the release next week. |
Affects: Framework 6.1.10 (most likely also 6.1.9)
Disclaimer: I have a hard time digging into this issue, because most of the concepts here are new to me. I might use the terminology wrong or be way off with my assessment.
We experienced a change with Framework 6.1.8 where AspectJ related Mockito tests started failing, most likely related to #32970
However, instead of being executed twice there were now 3 calls for one method.
Besides the actual delegate and the cglib proxy (as described in the issue) there was another call from a Mockito mock instance with a cglib proxy - at least I think that is what the debugger indicates: a call from
MyService$MockitoMock$<somerandomstuff>$$SpringCGLIB$$0
Since we only manage the spring-boot version directly, we tested the backported fix (I think it is this one: 628b050) using framework version 6.1.10 (spring-boot update to 3.2.7).
The tests still fail because there are still two calls. The CTW cglib proxy call has been fixed, but there is still the Mockito mock related one.
At least that is what it looks like to me.
The text was updated successfully, but these errors were encountered: