Change enforceOverride flag to false in @TestBean and @MockitoBean
Based on feedback from the Spring Boot team, we have decided to change the default values for the enforceOverride flags in @TestBean and @MockitoBean from true to false. Closes gh-33613
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
= `@MockitoBean` and `@MockitoSpyBean`
|
||||
|
||||
`@MockitoBean` and `@MockitoSpyBean` are used on fields in test classes to override beans
|
||||
in the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the
|
||||
in the test's `ApplicationContext` with a Mockito _mock_ or _spy_, respectively. In the
|
||||
latter case, the original bean definition is not replaced, but instead an early instance
|
||||
of the bean is captured and wrapped by the spy.
|
||||
|
||||
@@ -11,9 +11,10 @@ to override. If multiple candidates match, `@Qualifier` can be provided to narro
|
||||
candidate to override. Alternatively, a candidate whose bean definition name matches the
|
||||
name of the field will match.
|
||||
|
||||
When using `@MockitoBean`, if you would like for a new bean definition to be created when
|
||||
a corresponding bean definition does not exist, set the `enforceOverride` attribute to
|
||||
`false` – for example, `@MockitoBean(enforceOverride = false)`.
|
||||
When using `@MockitoBean`, a new bean definition will be created if a corresponding bean
|
||||
definition does not exist. However, if you would like for the test to fail when a
|
||||
corresponding bean definition does not exist, you can set the `enforceOverride` attribute
|
||||
to `true` – for example, `@MockitoBean(enforceOverride = true)`.
|
||||
|
||||
To use a by-name override rather than a by-type override, specify the `name` attribute
|
||||
of the annotation.
|
||||
|
||||
@@ -15,9 +15,10 @@ to override. If multiple candidates match, `@Qualifier` can be provided to narro
|
||||
candidate to override. Alternatively, a candidate whose bean definition name matches the
|
||||
name of the field will match.
|
||||
|
||||
If you would like for a new bean definition to be created when a corresponding bean
|
||||
definition does not exist, set the `enforceOverride` attribute to `false` – for example,
|
||||
`@TestBean(enforceOverride = false)`.
|
||||
A new bean definition will be created if a corresponding bean definition does not exist.
|
||||
However, if you would like for the test to fail when a corresponding bean definition does
|
||||
not exist, you can set the `enforceOverride` attribute to `true` – for example,
|
||||
`@TestBean(enforceOverride = true)`.
|
||||
|
||||
To use a by-name override rather than a by-type override, specify the `name` attribute
|
||||
of the annotation.
|
||||
|
||||
@@ -31,16 +31,17 @@ import org.springframework.test.context.bean.override.BeanOverride;
|
||||
* {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* using a static factory method.
|
||||
*
|
||||
* <p>By default, the bean to override is inferred from the type of the
|
||||
* annotated field. This requires that exactly one matching bean definition is
|
||||
* present in the application context. A {@code @Qualifier} annotation can be
|
||||
* <p>By default, the bean to override is inferred from the type of the annotated
|
||||
* field. If multiple candidates exist, a {@code @Qualifier} annotation can be
|
||||
* used to help disambiguate. In the absence of a {@code @Qualifier} annotation,
|
||||
* the name of the annotated field will be used as a qualifier. Alternatively,
|
||||
* you can explicitly specify a bean name to replace by setting the
|
||||
* {@link #value() value} or {@link #name() name} attribute. If you would like
|
||||
* for a new bean definition to be created when a corresponding bean definition
|
||||
* does not exist, set the {@link #enforceOverride() enforceOverride} attribute
|
||||
* to {@code false}.
|
||||
* the name of the annotated field will be used as a fallback qualifier.
|
||||
* Alternatively, you can explicitly specify a bean name to replace by setting the
|
||||
* {@link #value() value} or {@link #name() name} attribute.
|
||||
*
|
||||
* <p>A new bean definition will be created if a corresponding bean definition does
|
||||
* not exist. However, if you would like for the test to fail when a corresponding
|
||||
* bean definition does not exist, you can set the {@link #enforceOverride()
|
||||
* enforceOverride} attribute to {@code true}.
|
||||
*
|
||||
* <p>The instance is created from a zero-argument static factory method in the
|
||||
* test class whose return type is compatible with the annotated field. In the
|
||||
@@ -149,13 +150,13 @@ public @interface TestBean {
|
||||
/**
|
||||
* Whether to require the existence of a bean definition for the bean being
|
||||
* overridden.
|
||||
* <p>Defaults to {@code true} which means that an exception will be thrown
|
||||
* if a corresponding bean definition does not exist.
|
||||
* <p>Set to {@code false} to create a new bean definition when a corresponding
|
||||
* <p>Defaults to {@code false} which means that a new bean definition will
|
||||
* be created if a corresponding bean definition does not exist.
|
||||
* <p>Set to {@code true} to cause an exception to be thrown if a corresponding
|
||||
* bean definition does not exist.
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_OR_CREATE_DEFINITION
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
|
||||
*/
|
||||
boolean enforceOverride() default true;
|
||||
boolean enforceOverride() default false;
|
||||
|
||||
}
|
||||
|
||||
@@ -33,14 +33,17 @@ import org.springframework.test.context.bean.override.BeanOverride;
|
||||
* {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* using a Mockito mock.
|
||||
*
|
||||
* <p>If no explicit {@link #name() name} is specified, a target bean definition
|
||||
* is selected according to the type of the annotated field, and there must be
|
||||
* exactly one such candidate definition in the context. Otherwise, a {@code @Qualifier}
|
||||
* annotation can be used to help disambiguate between multiple candidates. If a
|
||||
* {@link #name() name} is specified, by default a corresponding bean definition
|
||||
* must exist in the application context. If you would like for a new bean definition
|
||||
* to be created when a corresponding bean definition does not exist, set the
|
||||
* {@link #enforceOverride() enforceOverride} attribute to {@code false}.
|
||||
* <p>By default, the bean to override is inferred from the type of the annotated
|
||||
* field. If multiple candidates exist, a {@code @Qualifier} annotation can be
|
||||
* used to help disambiguate. In the absence of a {@code @Qualifier} annotation,
|
||||
* the name of the annotated field will be used as a fallback qualifier.
|
||||
* Alternatively, you can explicitly specify a bean name to replace by setting the
|
||||
* {@link #name() name} attribute.
|
||||
*
|
||||
* <p>A new bean definition will be created if a corresponding bean definition does
|
||||
* not exist. However, if you would like for the test to fail when a corresponding
|
||||
* bean definition does not exist, you can set the {@link #enforceOverride()
|
||||
* enforceOverride} attribute to {@code true}.
|
||||
*
|
||||
* <p>Dependencies that are known to the application context but are not beans
|
||||
* (such as those
|
||||
@@ -105,13 +108,13 @@ public @interface MockitoBean {
|
||||
/**
|
||||
* Whether to require the existence of a bean definition for the bean being
|
||||
* overridden.
|
||||
* <p>Defaults to {@code true} which means that an exception will be thrown
|
||||
* if a corresponding bean definition does not exist.
|
||||
* <p>Set to {@code false} to create a new bean definition when a corresponding
|
||||
* <p>Defaults to {@code false} which means that a new bean definition will
|
||||
* be created if a corresponding bean definition does not exist.
|
||||
* <p>Set to {@code true} to cause an exception to be thrown if a corresponding
|
||||
* bean definition does not exist.
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_OR_CREATE_DEFINITION
|
||||
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
|
||||
*/
|
||||
boolean enforceOverride() default true;
|
||||
boolean enforceOverride() default false;
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class MockitoBeanJupiterTests {
|
||||
/**
|
||||
* Mock for nonexistent bean.
|
||||
*/
|
||||
@MockitoBean(enforceOverride = false)
|
||||
@MockitoBean
|
||||
GreetingService greetingService;
|
||||
|
||||
/**
|
||||
|
||||
@@ -420,7 +420,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
||||
static class CaseByNameWithQualifier {
|
||||
|
||||
@Qualifier("preferThis")
|
||||
@TestBean(name = "descriptionBean", enforceOverride = false)
|
||||
@TestBean(name = "descriptionBean")
|
||||
private String description;
|
||||
|
||||
static String descriptionBean() {
|
||||
|
||||
@@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@SpringJUnitConfig
|
||||
public class TestBeanForByTypeLookupIntegrationTests {
|
||||
|
||||
@TestBean(enforceOverride = false)
|
||||
@TestBean
|
||||
MessageService messageService;
|
||||
|
||||
@TestBean
|
||||
|
||||
@@ -126,7 +126,7 @@ public class TestBeanTests {
|
||||
|
||||
static class FailureByTypeLookup {
|
||||
|
||||
@TestBean
|
||||
@TestBean(enforceOverride = true)
|
||||
private String example;
|
||||
|
||||
static String example() {
|
||||
@@ -136,7 +136,7 @@ public class TestBeanTests {
|
||||
|
||||
static class FailureByNameLookup {
|
||||
|
||||
@TestBean(name = "beanToOverride")
|
||||
@TestBean(name = "beanToOverride", enforceOverride = true)
|
||||
private String example;
|
||||
|
||||
static String example() {
|
||||
|
||||
@@ -48,10 +48,10 @@ public class MockitoBeanForByNameLookupIntegrationTests {
|
||||
@MockitoBean(name = "nestedField")
|
||||
ExampleService renamed2;
|
||||
|
||||
@MockitoBean(name = "nonExistingBean", enforceOverride = false)
|
||||
@MockitoBean(name = "nonExistingBean")
|
||||
ExampleService nonExisting1;
|
||||
|
||||
@MockitoBean(name = "nestedNonExistingBean", enforceOverride = false)
|
||||
@MockitoBean(name = "nestedNonExistingBean")
|
||||
ExampleService nonExisting2;
|
||||
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
@SpringJUnitConfig
|
||||
public class MockitoBeanForByTypeLookupIntegrationTests {
|
||||
|
||||
@MockitoBean(enforceOverride = false)
|
||||
@MockitoBean
|
||||
AnotherService serviceIsNotABean;
|
||||
|
||||
@MockitoBean(enforceOverride = false)
|
||||
@MockitoBean
|
||||
ExampleService anyNameForService;
|
||||
|
||||
@MockitoBean
|
||||
|
||||
@@ -93,7 +93,7 @@ class MockitoBeanSettingsStrictIntegrationTests {
|
||||
@DirtiesContext
|
||||
static class ImplicitStrictnessWithMockitoBean extends BaseCase {
|
||||
|
||||
@MockitoBean(enforceOverride = false)
|
||||
@MockitoBean
|
||||
@SuppressWarnings("unused")
|
||||
DateTimeFormatter ignoredMock;
|
||||
}
|
||||
|
||||
@@ -29,27 +29,71 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
* Tests for {@link MockitoBean}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class MockitoMockBeanTests {
|
||||
|
||||
@Test
|
||||
void contextCustomizerCannotBeCreatedWithTooManyCandidates() {
|
||||
void cannotOverrideBeanByNameWithNoSuchBeanName() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBean("anotherBean", String.class, () -> "example");
|
||||
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByNameLookup.class, context);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessage("""
|
||||
Unable to override bean: there is no bean definition \
|
||||
to replace with name [beanToOverride] and type [java.lang.String].""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotOverrideBeanByNameWithBeanOfWrongType() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBean("beanToOverride", Integer.class, () -> 42);
|
||||
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByNameLookup.class, context);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessage("""
|
||||
Unable to override bean: there is no bean definition \
|
||||
to replace with name [beanToOverride] and type [java.lang.String].""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotOverrideBeanByTypeWithNoSuchBeanType() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByTypeLookup.class, context);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessage("""
|
||||
Unable to override bean: no bean definitions of \
|
||||
type %s (as required by annotated field '%s.example')""".formatted(
|
||||
String.class.getName(), FailureByTypeLookup.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotOverrideBeanByTypeWithTooManyBeansOfThatType() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.registerBean("bean1", String.class, () -> "example1");
|
||||
context.registerBean("bean2", String.class, () -> "example2");
|
||||
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(ByTypeSingleLookup.class, context);
|
||||
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByTypeLookup.class, context);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessage("""
|
||||
Unable to select a bean definition to override: found 2 bean definitions \
|
||||
of type %s (as required by annotated field '%s.example'): %s""",
|
||||
String.class.getName(), ByTypeSingleLookup.class.getSimpleName(), List.of("bean1", "bean2"));
|
||||
of type %s (as required by annotated field '%s.example'): %s""".formatted(
|
||||
String.class.getName(), FailureByTypeLookup.class.getSimpleName(), List.of("bean1", "bean2")));
|
||||
}
|
||||
|
||||
|
||||
static class ByTypeSingleLookup {
|
||||
static class FailureByTypeLookup {
|
||||
|
||||
@MockitoBean
|
||||
@MockitoBean(enforceOverride = true)
|
||||
String example;
|
||||
|
||||
}
|
||||
|
||||
static class FailureByNameLookup {
|
||||
|
||||
@MockitoBean(name = "beanToOverride", enforceOverride = true)
|
||||
String example;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user