version:Spring Boot 1.5.4.RELEASE
Is it normal that a bean defined with @MockBean isn't picked up by @ConditionalOnBean?
@lpandzic we don't use the tracker for questions. Please ask on Gitter or StackOverflow. If you believe you've found a bug in Spring Boot, rather than asking a question, please post a sample that reproduce the issues you're experiencing and we can reopen.
To follow up in case someone is wondering, here is the discussion on Gitter
If @MockBean creates a new instance (i.e. doesn't mock an existing bean in the context) that happens _way_ too late to have any sort of impact on auto-configuration.
I'm not agree with the rationale exposed but I'll respect it. Precisely to test @ConditionalOnBeans whats a best way than mocking the existance on the dependent bean from the test? If not we need to dirty the @Configuration class for test context and expose a dummy implementation. Thanks a lot for the fast clarification
It isn't clear what rationale it is you don't agree with but the Javadoc is there to avoid that kind of misuse. You can't test your conditions (or whatever it is your auto-configuration is doing) by mocking things in tests. Looking at Spring Boot's auto-configuration test suite should give you enough inspiration (TL;DR: you need to start a context in each test that simulates what configuration the user has provided, what configuration they contributed to the environment and the auto-configuration(s) you want to test).
In 2.0, we've rationalized that pattern in ContextLoader.
If you have more questions please ask on gitter or StackOverflow.
Thanks for all that information, snicoll. What I meant is that I am agree with lpandzic in that the case we use seems like the obvious default to a newcomer (regardless it's technically valid/justified or not)
@nightswimmings, that is exactly why I suggested to @snicoll that this be brought up to this issue and not left on gitter, which isn't indexed by google.
I'm still of opinion that @MockBean should have exact behaviour as manual mocking with @Bean, otherwise @MockBean seems like a hack that won't always work and people will spend time debugging something that isn't immediately clear.
As part of the discussion on Gitter, @snicoll said:
the context fully starts, then we start to parse your test and we lock for the
@MockBeanannotation
Strictly speaking, that isn't what happens. It's MockitoTestExecutionListener that runs after the context has started, but the registration of @MockBeans is done by MockitoPostProcessor.
MockitoPostProcessor is a BeanFactoryPostProcessor that is registered with the application context before it's refreshed. MockitoPostProcessor runs as part of the context being refreshed per the standard contract for a BeanFactoryPostProcessor. The problem arises because it runs after ConfigurationClassPostProcessor which is a PriorityOrdered BeanDefinitionRegistryPostProcessor. As a result, ConfigurationClassPostProcessor loads bean definitions and triggers evaluation of bean-based conditions before MockitoPostProcessor has had a change to register the definitions for the mock beans.
To avoid the problem, MockitoPostProcessor would have to become a PriorityOrdered BeanDefinitionRegistryPostProcessor with higher precedence than ConfigurationClassPostProcessor. However, I have no idea at this stage if that's even possible. I'd like to use this issue to investigate that possibility a bit more so I'm going to re-open it.
For the record, the problem doesn't occur with a @Bean method on a test class that produces a mock as the definition for this bean is added to the registry before ConfigurationClassPostProcessor triggers the evaluation of bean-based conditions on auto-configuration classes.
We've just revisited this one and changing the ordering won't work. If MockitoPostProcessor goes before ConfigurationClassPostProcessor it will no longer be able to replace a bean defined in a configuration class with a mock. Unfortunately, this means that we don't think it's feasible to fix this one. We recommend that you use a manually defined @Bean method to define the mock instead.