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
@MockBean and @SpyBean without amending the application context #34768
Comments
I hadn't seen Mock in Bean before. Thanks for the pointer to it.
The behavior implemented by Mock in Bean seems to be subtly different. Rather than replacing beans with mocks/spies in the application context for the specific test, it replaces the value of a field in a bean for the duration of a test. While clever, I think this approach may come with too many caveats to include in Spring Boot itself. For example, I believe it only works when the item that you want to mock or spy is held in a field of a bean. It also requires this field to be mutated. That either impedes constructor-based injection and immutability or it requires reflective hacks to set a One problem with replacing things at the bean level on a test-by-test basis is that we don't know where those beans have been injected or how they've been used while the context was being refreshed. This makes it very hard to swap in a mock or spy for the duration of a test in every place where that is needed. One option is to lazily proxy everything and then return the actual bean, a mock, or a spy, on a test-by-test basis but this brings with it a number of different problems. I can certainly see the appeal of being able to mock and spy different beans in different tests without it resulting in many different application contexts being created. It's something that's come up more than once over the years but we've been unable to think of a good way to do it that doesn't introduce too many caveats and drawbacks. I'll leave this issue open so that we can think about it again. |
Hey @wilkinsona @maciejwalkowiak , Good day! Awaiting your response |
Thanks for your interest in contributing, @ramananrpn. We don't know what, if anything, we can do to address this requirement so it isn't a great place to get started. I'm not sure if we have any at the moment, but please keep an eye out for unassigned issues labelled with ideal for contribution or, as your haven't contributed before, first-timers only. |
Thanks @wilkinsona . Ill keep an eye in this |
@MockBean
and @SpyBean
without amending the application context
I'm successfully using the following technique on my projects to avoid this problem: @AutoConfiguration
public class TestOverridesConfiguration {
@Primary
@Bean
public ExternalService externalServiceMock(@Qualifier("externalService") final ExternalService real) {
return Mockito.mock(ExternalService.class, AdditionalAnswers.delegatesTo(real));
} with a custom TestExecutionListener that resets the mocks around every test. It can probably be improved in several ways, but it is good enough for me for now. E.g. this could be wrapped semi-automatically with BeanPostProcessor, or something like that, similarly to what Spring is doing with Hibernate's EntityManager. |
Hey @wilkinsona I'd be interested in your opinion on @fprochazka 's approach (also see his blog post). Do you see any caveats that people should be aware of before following this? |
It feels similar to |
There is a library that tackles this problem MockInBean |
Mock In Bean has already been discussed in this very issue. Please see the opening comment and my first reply. |
Not sure How I missed that! |
@wilkinsona , getting back to that original comment.
Could you please elaborate on those different problems you are concerned with? |
Proxying isn't without its problems and can change behavior in subtle and unpredictable ways, particularly with final classes, classes that have already been proxied, classes that call methods on themselves, and so on. Proxying every bean in the context brings those possible changes in behavior to every bean in the context and does so only for tests. |
This is more an idea for enhancement rather than an issue.
@MockBean
and@SpyBean
are designed in a way that using them amends the application context. Using them in any bigger application requires care and understanding how Spring context caching works and how to optimize tests structure to avoid creating many application contexts.Perhaps there is an option to change the behavior of
@MockBean
and@SpyBean
to replace beans with mocks/spies in application context for the specific test case, and then replace them back with original objects. This way, these annotations would not trigger creation of the new application context.Such behavior has been implemented in https://github.com/antoinemeyer/mock-in-bean/. The biggest problem I see with this approach is executing tests in parallel.
The text was updated successfully, but these errors were encountered: