Closed mwisnicki closed 7 months ago
We think this is an interesting idea, but something that could be implemented in Spring Framework rather than Spring Boot. We'll transfer the issue for the Framework team to consider.
Or introduce an option to define which bean names or classes can be overridden. For example in Spring Boot will be this property:
spring.main.allow-bean-definition-overriding-names=myBean
and then you can override only a bean with the name myBean
It would be great if there was a single annotation that allowed overriding single bean in testing, e.g.:
Unfortunately, the code snippet you've provided wouldn't work. A test class can't be a @Configuration
class as we process it after the actual test context has been refreshed. Ignoring that, a method callback isn't great as the instantiation of the bean to override would happen before the test class itself is initialized. The method has to be static (like many other callbacks in tests).
Even better if it could be relaxed to support field instead of method.
I am not sure how that would look like, but it means we have to instantiate the test instance before refreshing the context (since the bean factory can instantiate that bean at any point in time).
Brainstorming with @simonbasle, we're considering several options. First an infrastructure that is inspired by the @MockBean
and @SpyBean
support in Spring Boot. Not replacing it but providing the building blocks so that the Spring Boot counterpart can really focus on the feature and not the plumbing. Then, a way to flag a field for overriding. To be consistent, the value should be replaced in the bean factory. An example of such usage could be:
class MyTest {
@MethodOverride
private MyBean myBean;
static MyBean myBeanValueSupplier() {
return new MyBean();
}
Where @MethodOverride
is one implementation, here based on a naming convention for the method. It can be used to override the bean, based on a more generic contract. For other use cases, you could define your own annotation and/or provide the implementation of a "processor" that would perform the swapping.
Does that make sense? Any feedback on the proposal?
Please note that this has been addressed by @simonbasle in commit e1bbdf09139dca7c21ec64e140bcc3bda463b2f6 which:
Introduces two sets of annotations (
@TestBean
on one side and@MockitoBean
/@MockitoSpyBean
on the other side), as well as an extension mechanism based on a new@BeanOverride
meta-annotation.Extension implementers are expected to only provide an annotation, a
BeanOverrideProcessor
implementation, and anOverrideMetadata
subclass.
The new @MockitoBean
and @MockitoSpyBean
annotations in Spring Framework are analogous to the existing @MockBean
and @SpyBean
annotations in Spring Boot.
Hi @sbrannen - question on the new annotations:
MockBean
supported targeting either fields or types. MockitoBean
only targets fields, and I don't see an obvious replacement for the MockBean
behavior to target types.
This was useful for test cases which wanted to stub out some set of beans (ie to avoid some side effect of regular instantiation), but didn't care about specifying behavior.
Is that feature intentionally dropped? Or is it just not-yet-added? Is there discussion on this somewhere?
Overriding beans in testing is commonly needed yet current approach is unnecessarily complicated and at the same time limited and very error prone (allow-bean-definition-overriding will hide other issues). For example see spring-projects/spring-boot#30513
It would be great if there was a single annotation that allowed overriding single bean in testing, e.g.:
Even better if it could be relaxed to support field instead of method.