Skip to content

Commit 1afcb22

Browse files
committed
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
1 parent 381b16f commit 1afcb22

File tree

12 files changed

+100
-50
lines changed

12 files changed

+100
-50
lines changed

framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-mockitobean.adoc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
= `@MockitoBean` and `@MockitoSpyBean`
33

44
`@MockitoBean` and `@MockitoSpyBean` are used on fields in test classes to override beans
5-
in the test's `ApplicationContext` with a Mockito mock or spy, respectively. In the
5+
in the test's `ApplicationContext` with a Mockito _mock_ or _spy_, respectively. In the
66
latter case, the original bean definition is not replaced, but instead an early instance
77
of the bean is captured and wrapped by the spy.
88

@@ -11,9 +11,10 @@ to override. If multiple candidates match, `@Qualifier` can be provided to narro
1111
candidate to override. Alternatively, a candidate whose bean definition name matches the
1212
name of the field will match.
1313

14-
When using `@MockitoBean`, if you would like for a new bean definition to be created when
15-
a corresponding bean definition does not exist, set the `enforceOverride` attribute to
16-
`false` – for example, `@MockitoBean(enforceOverride = false)`.
14+
When using `@MockitoBean`, a new bean definition will be created if a corresponding bean
15+
definition does not exist. However, if you would like for the test to fail when a
16+
corresponding bean definition does not exist, you can set the `enforceOverride` attribute
17+
to `true` – for example, `@MockitoBean(enforceOverride = true)`.
1718

1819
To use a by-name override rather than a by-type override, specify the `name` attribute
1920
of the annotation.

framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testbean.adoc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ to override. If multiple candidates match, `@Qualifier` can be provided to narro
1515
candidate to override. Alternatively, a candidate whose bean definition name matches the
1616
name of the field will match.
1717

18-
If you would like for a new bean definition to be created when a corresponding bean
19-
definition does not exist, set the `enforceOverride` attribute to `false` – for example,
20-
`@TestBean(enforceOverride = false)`.
18+
A new bean definition will be created if a corresponding bean definition does not exist.
19+
However, if you would like for the test to fail when a corresponding bean definition does
20+
not exist, you can set the `enforceOverride` attribute to `true` – for example,
21+
`@TestBean(enforceOverride = true)`.
2122

2223
To use a by-name override rather than a by-type override, specify the `name` attribute
2324
of the annotation.

spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBean.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,17 @@
3131
* {@link org.springframework.context.ApplicationContext ApplicationContext}
3232
* using a static factory method.
3333
*
34-
* <p>By default, the bean to override is inferred from the type of the
35-
* annotated field. This requires that exactly one matching bean definition is
36-
* present in the application context. A {@code @Qualifier} annotation can be
34+
* <p>By default, the bean to override is inferred from the type of the annotated
35+
* field. If multiple candidates exist, a {@code @Qualifier} annotation can be
3736
* used to help disambiguate. In the absence of a {@code @Qualifier} annotation,
38-
* the name of the annotated field will be used as a qualifier. Alternatively,
39-
* you can explicitly specify a bean name to replace by setting the
40-
* {@link #value() value} or {@link #name() name} attribute. If you would like
41-
* for a new bean definition to be created when a corresponding bean definition
42-
* does not exist, set the {@link #enforceOverride() enforceOverride} attribute
43-
* to {@code false}.
37+
* the name of the annotated field will be used as a fallback qualifier.
38+
* Alternatively, you can explicitly specify a bean name to replace by setting the
39+
* {@link #value() value} or {@link #name() name} attribute.
40+
*
41+
* <p>A new bean definition will be created if a corresponding bean definition does
42+
* not exist. However, if you would like for the test to fail when a corresponding
43+
* bean definition does not exist, you can set the {@link #enforceOverride()
44+
* enforceOverride} attribute to {@code true}.
4445
*
4546
* <p>The instance is created from a zero-argument static factory method in the
4647
* test class whose return type is compatible with the annotated field. In the
@@ -149,13 +150,13 @@
149150
/**
150151
* Whether to require the existence of a bean definition for the bean being
151152
* overridden.
152-
* <p>Defaults to {@code true} which means that an exception will be thrown
153-
* if a corresponding bean definition does not exist.
154-
* <p>Set to {@code false} to create a new bean definition when a corresponding
153+
* <p>Defaults to {@code false} which means that a new bean definition will
154+
* be created if a corresponding bean definition does not exist.
155+
* <p>Set to {@code true} to cause an exception to be thrown if a corresponding
155156
* bean definition does not exist.
156-
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
157157
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_OR_CREATE_DEFINITION
158+
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
158159
*/
159-
boolean enforceOverride() default true;
160+
boolean enforceOverride() default false;
160161

161162
}

spring-test/src/main/java/org/springframework/test/context/bean/override/mockito/MockitoBean.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@
3333
* {@link org.springframework.context.ApplicationContext ApplicationContext}
3434
* using a Mockito mock.
3535
*
36-
* <p>If no explicit {@link #name() name} is specified, a target bean definition
37-
* is selected according to the type of the annotated field, and there must be
38-
* exactly one such candidate definition in the context. Otherwise, a {@code @Qualifier}
39-
* annotation can be used to help disambiguate between multiple candidates. If a
40-
* {@link #name() name} is specified, by default a corresponding bean definition
41-
* must exist in the application context. If you would like for a new bean definition
42-
* to be created when a corresponding bean definition does not exist, set the
43-
* {@link #enforceOverride() enforceOverride} attribute to {@code false}.
36+
* <p>By default, the bean to override is inferred from the type of the annotated
37+
* field. If multiple candidates exist, a {@code @Qualifier} annotation can be
38+
* used to help disambiguate. In the absence of a {@code @Qualifier} annotation,
39+
* the name of the annotated field will be used as a fallback qualifier.
40+
* Alternatively, you can explicitly specify a bean name to replace by setting the
41+
* {@link #name() name} attribute.
42+
*
43+
* <p>A new bean definition will be created if a corresponding bean definition does
44+
* not exist. However, if you would like for the test to fail when a corresponding
45+
* bean definition does not exist, you can set the {@link #enforceOverride()
46+
* enforceOverride} attribute to {@code true}.
4447
*
4548
* <p>Dependencies that are known to the application context but are not beans
4649
* (such as those
@@ -105,13 +108,13 @@
105108
/**
106109
* Whether to require the existence of a bean definition for the bean being
107110
* overridden.
108-
* <p>Defaults to {@code true} which means that an exception will be thrown
109-
* if a corresponding bean definition does not exist.
110-
* <p>Set to {@code false} to create a new bean definition when a corresponding
111+
* <p>Defaults to {@code false} which means that a new bean definition will
112+
* be created if a corresponding bean definition does not exist.
113+
* <p>Set to {@code true} to cause an exception to be thrown if a corresponding
111114
* bean definition does not exist.
112-
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
113115
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_OR_CREATE_DEFINITION
116+
* @see org.springframework.test.context.bean.override.BeanOverrideStrategy#REPLACE_DEFINITION
114117
*/
115-
boolean enforceOverride() default true;
118+
boolean enforceOverride() default false;
116119

117120
}

spring-test/src/test/java/org/springframework/test/context/aot/samples/bean/override/MockitoBeanJupiterTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class MockitoBeanJupiterTests {
4040
/**
4141
* Mock for nonexistent bean.
4242
*/
43-
@MockitoBean(enforceOverride = false)
43+
@MockitoBean
4444
GreetingService greetingService;
4545

4646
/**

spring-test/src/test/java/org/springframework/test/context/bean/override/BeanOverrideBeanFactoryPostProcessorTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ static class CaseOverrideBeanProducedByFactoryBean {
420420
static class CaseByNameWithQualifier {
421421

422422
@Qualifier("preferThis")
423-
@TestBean(name = "descriptionBean", enforceOverride = false)
423+
@TestBean(name = "descriptionBean")
424424
private String description;
425425

426426
static String descriptionBean() {

spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanForByTypeLookupIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
@SpringJUnitConfig
4040
public class TestBeanForByTypeLookupIntegrationTests {
4141

42-
@TestBean(enforceOverride = false)
42+
@TestBean
4343
MessageService messageService;
4444

4545
@TestBean

spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void contextCustomizerCannotBeCreatedWitCompetingOverrideMethods() {
126126

127127
static class FailureByTypeLookup {
128128

129-
@TestBean
129+
@TestBean(enforceOverride = true)
130130
private String example;
131131

132132
static String example() {
@@ -136,7 +136,7 @@ static String example() {
136136

137137
static class FailureByNameLookup {
138138

139-
@TestBean(name = "beanToOverride")
139+
@TestBean(name = "beanToOverride", enforceOverride = true)
140140
private String example;
141141

142142
static String example() {

spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByNameLookupIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ public class MockitoBeanForByNameLookupIntegrationTests {
4848
@MockitoBean(name = "nestedField")
4949
ExampleService renamed2;
5050

51-
@MockitoBean(name = "nonExistingBean", enforceOverride = false)
51+
@MockitoBean(name = "nonExistingBean")
5252
ExampleService nonExisting1;
5353

54-
@MockitoBean(name = "nestedNonExistingBean", enforceOverride = false)
54+
@MockitoBean(name = "nestedNonExistingBean")
5555
ExampleService nonExisting2;
5656

5757

spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForByTypeLookupIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
@SpringJUnitConfig
4949
public class MockitoBeanForByTypeLookupIntegrationTests {
5050

51-
@MockitoBean(enforceOverride = false)
51+
@MockitoBean
5252
AnotherService serviceIsNotABean;
5353

54-
@MockitoBean(enforceOverride = false)
54+
@MockitoBean
5555
ExampleService anyNameForService;
5656

5757
@MockitoBean

spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanSettingsStrictIntegrationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ static class ExplicitStrictness extends BaseCase {
9393
@DirtiesContext
9494
static class ImplicitStrictnessWithMockitoBean extends BaseCase {
9595

96-
@MockitoBean(enforceOverride = false)
96+
@MockitoBean
9797
@SuppressWarnings("unused")
9898
DateTimeFormatter ignoredMock;
9999
}

spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoMockBeanTests.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,71 @@
2929
* Tests for {@link MockitoBean}.
3030
*
3131
* @author Stephane Nicoll
32+
* @author Sam Brannen
3233
*/
3334
class MockitoMockBeanTests {
3435

3536
@Test
36-
void contextCustomizerCannotBeCreatedWithTooManyCandidates() {
37+
void cannotOverrideBeanByNameWithNoSuchBeanName() {
38+
GenericApplicationContext context = new GenericApplicationContext();
39+
context.registerBean("anotherBean", String.class, () -> "example");
40+
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByNameLookup.class, context);
41+
assertThatIllegalStateException()
42+
.isThrownBy(context::refresh)
43+
.withMessage("""
44+
Unable to override bean: there is no bean definition \
45+
to replace with name [beanToOverride] and type [java.lang.String].""");
46+
}
47+
48+
@Test
49+
void cannotOverrideBeanByNameWithBeanOfWrongType() {
50+
GenericApplicationContext context = new GenericApplicationContext();
51+
context.registerBean("beanToOverride", Integer.class, () -> 42);
52+
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByNameLookup.class, context);
53+
assertThatIllegalStateException()
54+
.isThrownBy(context::refresh)
55+
.withMessage("""
56+
Unable to override bean: there is no bean definition \
57+
to replace with name [beanToOverride] and type [java.lang.String].""");
58+
}
59+
60+
@Test
61+
void cannotOverrideBeanByTypeWithNoSuchBeanType() {
62+
GenericApplicationContext context = new GenericApplicationContext();
63+
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByTypeLookup.class, context);
64+
assertThatIllegalStateException()
65+
.isThrownBy(context::refresh)
66+
.withMessage("""
67+
Unable to override bean: no bean definitions of \
68+
type %s (as required by annotated field '%s.example')""".formatted(
69+
String.class.getName(), FailureByTypeLookup.class.getSimpleName()));
70+
}
71+
72+
@Test
73+
void cannotOverrideBeanByTypeWithTooManyBeansOfThatType() {
3774
GenericApplicationContext context = new GenericApplicationContext();
3875
context.registerBean("bean1", String.class, () -> "example1");
3976
context.registerBean("bean2", String.class, () -> "example2");
40-
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(ByTypeSingleLookup.class, context);
77+
BeanOverrideContextCustomizerTestUtils.customizeApplicationContext(FailureByTypeLookup.class, context);
4178
assertThatIllegalStateException()
4279
.isThrownBy(context::refresh)
4380
.withMessage("""
4481
Unable to select a bean definition to override: found 2 bean definitions \
45-
of type %s (as required by annotated field '%s.example'): %s""",
46-
String.class.getName(), ByTypeSingleLookup.class.getSimpleName(), List.of("bean1", "bean2"));
82+
of type %s (as required by annotated field '%s.example'): %s""".formatted(
83+
String.class.getName(), FailureByTypeLookup.class.getSimpleName(), List.of("bean1", "bean2")));
4784
}
4885

4986

50-
static class ByTypeSingleLookup {
87+
static class FailureByTypeLookup {
88+
89+
@MockitoBean(enforceOverride = true)
90+
String example;
91+
92+
}
93+
94+
static class FailureByNameLookup {
5195

52-
@MockitoBean
96+
@MockitoBean(name = "beanToOverride", enforceOverride = true)
5397
String example;
5498

5599
}

0 commit comments

Comments
 (0)