Introduce enforceOverride flag in @⁠TestBean and @⁠MockitoBean

Prior to this commit, @⁠MockitoBean could be used to either create or
replace a bean definition, but @⁠TestBean could only be used to replace
a bean definition.

However, Bean Override implementations should require the presence of
an existing bean definition by default (i.e. literally "override" by
default), while giving the user the option to have a new bean
definition created if desired.

To address that, this commit introduces a new `enforceOverride`
attribute in @⁠TestBean and @⁠MockitoBean that defaults to true but
allows the user to decide if it's OK to create a bean for a nonexistent
bean definition.

Closes gh-33613
This commit is contained in:
Sam Brannen
2024-09-30 14:24:14 +02:00
parent 30dc86810e
commit 1c87e4795d
12 changed files with 103 additions and 31 deletions

View File

@@ -39,6 +39,9 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringJUnitConfig
public class TestBeanForByTypeLookupIntegrationTests {
@TestBean(enforceOverride = false)
MessageService messageService;
@TestBean
ExampleService anyNameForService;
@@ -50,6 +53,11 @@ public class TestBeanForByTypeLookupIntegrationTests {
@CustomQualifier
StringBuilder anyNameForStringBuilder2;
static MessageService messageService() {
return () -> "mocked nonexistent bean definition";
}
static ExampleService anyNameForService() {
return new RealExampleService("Mocked greeting");
}
@@ -63,6 +71,12 @@ public class TestBeanForByTypeLookupIntegrationTests {
}
@Test
void overrideIsFoundByTypeForNonexistentBeanDefinition(ApplicationContext ctx) {
assertThat(this.messageService).isSameAs(ctx.getBean(MessageService.class));
assertThat(this.messageService.getMessage()).isEqualTo("mocked nonexistent bean definition");
}
@Test
void overrideIsFoundByType(ApplicationContext ctx) {
assertThat(this.anyNameForService)
@@ -114,4 +128,10 @@ public class TestBeanForByTypeLookupIntegrationTests {
}
}
@FunctionalInterface
interface MessageService {
String getMessage();
}
}

View File

@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ResolvableType;
import org.springframework.test.context.bean.override.BeanOverrideStrategy;
import org.springframework.test.context.bean.override.OverrideMetadata;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -124,7 +125,8 @@ class TestBeanOverrideMetadataTests {
private TestBeanOverrideMetadata createMetadata(Field field, Method overrideMethod) {
TestBean annotation = field.getAnnotation(TestBean.class);
String beanName = (StringUtils.hasText(annotation.name()) ? annotation.name() : null);
return new TestBeanOverrideMetadata(field, ResolvableType.forClass(field.getType()), beanName, overrideMethod);
return new TestBeanOverrideMetadata(
field, ResolvableType.forClass(field.getType()), beanName, BeanOverrideStrategy.REPLACE_DEFINITION, overrideMethod);
}
static class SampleOneOverride {

View File

@@ -48,10 +48,10 @@ public class MockitoBeanForByNameLookupIntegrationTests {
@MockitoBean(name = "nestedField")
ExampleService renamed2;
@MockitoBean(name = "nonExistingBean")
@MockitoBean(name = "nonExistingBean", enforceOverride = false)
ExampleService nonExisting1;
@MockitoBean(name = "nestedNonExistingBean")
@MockitoBean(name = "nestedNonExistingBean", enforceOverride = false)
ExampleService nonExisting2;

View File

@@ -48,10 +48,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
@SpringJUnitConfig
public class MockitoBeanForByTypeLookupIntegrationTests {
@MockitoBean
@MockitoBean(enforceOverride = false)
AnotherService serviceIsNotABean;
@MockitoBean
@MockitoBean(enforceOverride = false)
ExampleService anyNameForService;
@MockitoBean

View File

@@ -93,7 +93,7 @@ class MockitoBeanSettingsStrictIntegrationTests {
@DirtiesContext
static class ImplicitStrictnessWithMockitoBean extends BaseCase {
@MockitoBean
@MockitoBean(enforceOverride = false)
@SuppressWarnings("unused")
DateTimeFormatter ignoredMock;
}