Add support for bean overriding in tests
This commit introduces two sets of annotations (`@TestBean` on one side and `MockitoBean`/`MockitoSpyBean` on the other side), as well as an extension mecanism based on the `@BeanOverride` meta-annotation. Extension implementors are expected to only provide an annotation, a BeanOverrideProcessor implementation and an OverrideMetadata subclass. Closes gh-29917.
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.SimpleThreadScope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.test.bean.override.example.ExampleBeanOverrideAnnotation;
|
||||
import org.springframework.test.bean.override.example.ExampleService;
|
||||
import org.springframework.test.bean.override.example.FailingExampleService;
|
||||
import org.springframework.test.bean.override.example.RealExampleService;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
|
||||
/**
|
||||
* Test for {@link BeanOverrideBeanPostProcessor}.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
class BeanOverrideBeanPostProcessorTests {
|
||||
|
||||
BeanOverrideParser parser;
|
||||
|
||||
@BeforeEach
|
||||
void initParser() {
|
||||
this.parser = new BeanOverrideParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
void canReplaceExistingBeanDefinitions() {
|
||||
this.parser.parse(ReplaceBeans.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(ReplaceBeans.class);
|
||||
context.registerBean("explicit", ExampleService.class, () -> new RealExampleService("unexpected"));
|
||||
context.registerBean("implicitName", ExampleService.class, () -> new RealExampleService("unexpected"));
|
||||
|
||||
context.refresh();
|
||||
|
||||
assertThat(context.getBean("explicit")).isSameAs(OVERRIDE_SERVICE);
|
||||
assertThat(context.getBean("implicitName")).isSameAs(OVERRIDE_SERVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cannotReplaceIfNoBeanMatching() {
|
||||
this.parser.parse(ReplaceBeans.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(ReplaceBeans.class);
|
||||
//note we don't register any original bean here
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(context::refresh).withMessage("Unable to override test bean, " +
|
||||
"expected a bean definition to replace with name 'explicit'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void canReplaceExistingBeanDefinitionsWithCreateReplaceStrategy() {
|
||||
this.parser.parse(CreateIfOriginalIsMissingBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(CreateIfOriginalIsMissingBean.class);
|
||||
context.registerBean("explicit", ExampleService.class, () -> new RealExampleService("unexpected"));
|
||||
context.registerBean("implicitName", ExampleService.class, () -> new RealExampleService("unexpected"));
|
||||
|
||||
context.refresh();
|
||||
|
||||
assertThat(context.getBean("explicit")).isSameAs(OVERRIDE_SERVICE);
|
||||
assertThat(context.getBean("implicitName")).isSameAs(OVERRIDE_SERVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void canCreateIfOriginalMissingWithCreateReplaceStrategy() {
|
||||
this.parser.parse(CreateIfOriginalIsMissingBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(CreateIfOriginalIsMissingBean.class);
|
||||
//note we don't register original beans here
|
||||
|
||||
context.refresh();
|
||||
|
||||
assertThat(context.getBean("explicit")).isSameAs(OVERRIDE_SERVICE);
|
||||
assertThat(context.getBean("implicitName")).isSameAs(OVERRIDE_SERVICE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void canOverrideBeanProducedByFactoryBeanWithClassObjectTypeAttribute() {
|
||||
this.parser.parse(OverriddenFactoryBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, parser.getOverrideMetadata());
|
||||
RootBeanDefinition factoryBeanDefinition = new RootBeanDefinition(TestFactoryBean.class);
|
||||
factoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, SomeInterface.class);
|
||||
context.registerBeanDefinition("beanToBeOverridden", factoryBeanDefinition);
|
||||
context.register(OverriddenFactoryBean.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean("beanToBeOverridden")).isSameAs(OVERRIDE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void canOverrideBeanProducedByFactoryBeanWithResolvableTypeObjectTypeAttribute() {
|
||||
this.parser.parse(OverriddenFactoryBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
BeanOverrideBeanPostProcessor.register(context, parser.getOverrideMetadata());
|
||||
RootBeanDefinition factoryBeanDefinition = new RootBeanDefinition(TestFactoryBean.class);
|
||||
ResolvableType objectType = ResolvableType.forClass(SomeInterface.class);
|
||||
factoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, objectType);
|
||||
context.registerBeanDefinition("beanToBeOverridden", factoryBeanDefinition);
|
||||
context.register(OverriddenFactoryBean.class);
|
||||
context.refresh();
|
||||
assertThat(context.getBean("beanToBeOverridden")).isSameAs(OVERRIDE);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void postProcessorShouldNotTriggerEarlyInitialization() {
|
||||
this.parser.parse(EagerInitBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(FactoryBeanRegisteringPostProcessor.class);
|
||||
BeanOverrideBeanPostProcessor.register(context, parser.getOverrideMetadata());
|
||||
context.register(EarlyBeanInitializationDetector.class);
|
||||
context.register(EagerInitBean.class);
|
||||
|
||||
assertThatNoException().isThrownBy(context::refresh);
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowReplaceDefinitionWhenSingletonDefinitionPresent() {
|
||||
this.parser.parse(SingletonBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
||||
definition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||
context.registerBeanDefinition("singleton", definition);
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(SingletonBean.class);
|
||||
|
||||
assertThatNoException().isThrownBy(context::refresh);
|
||||
assertThat(context.isSingleton("singleton")).as("isSingleton").isTrue();
|
||||
assertThat(context.getBean("singleton")).as("overridden").isEqualTo("USED THIS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void copyDefinitionPrimaryAndScope() {
|
||||
this.parser.parse(SingletonBean.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.getBeanFactory().registerScope("customScope", new SimpleThreadScope());
|
||||
RootBeanDefinition definition = new RootBeanDefinition(String.class, () -> "ORIGINAL");
|
||||
definition.setScope("customScope");
|
||||
definition.setPrimary(true);
|
||||
context.registerBeanDefinition("singleton", definition);
|
||||
BeanOverrideBeanPostProcessor.register(context, this.parser.getOverrideMetadata());
|
||||
context.register(SingletonBean.class);
|
||||
|
||||
assertThatNoException().isThrownBy(context::refresh);
|
||||
assertThat(context.getBeanDefinition("singleton"))
|
||||
.isNotSameAs(definition)
|
||||
.matches(BeanDefinition::isPrimary, "isPrimary")
|
||||
.satisfies(d -> assertThat(d.getScope()).isEqualTo("customScope"))
|
||||
.matches(Predicate.not(BeanDefinition::isSingleton), "!isSingleton")
|
||||
.matches(Predicate.not(BeanDefinition::isPrototype), "!isPrototype");
|
||||
}
|
||||
|
||||
/*
|
||||
Classes to parse and register with the bean post processor
|
||||
-----
|
||||
Note that some of these are both a @Configuration class and bean override field holder.
|
||||
This is for this test convenience, as typically the bean override annotated fields
|
||||
should not be in configuration classes but rather in test case classes
|
||||
(where a TestExecutionListener automatically discovers and parses them).
|
||||
*/
|
||||
|
||||
static final SomeInterface OVERRIDE = new SomeImplementation();
|
||||
static final ExampleService OVERRIDE_SERVICE = new FailingExampleService();
|
||||
|
||||
static class ReplaceBeans {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "useThis", beanName = "explicit")
|
||||
private ExampleService explicitName;
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "useThis")
|
||||
private ExampleService implicitName;
|
||||
|
||||
static ExampleService useThis() {
|
||||
return OVERRIDE_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
static class CreateIfOriginalIsMissingBean {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "useThis", createIfMissing = true, beanName = "explicit")
|
||||
private ExampleService explicitName;
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "useThis", createIfMissing = true)
|
||||
private ExampleService implicitName;
|
||||
|
||||
static ExampleService useThis() {
|
||||
return OVERRIDE_SERVICE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class OverriddenFactoryBean {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "fOverride", beanName = "beanToBeOverridden")
|
||||
SomeInterface f;
|
||||
|
||||
static SomeInterface fOverride() {
|
||||
return OVERRIDE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestFactoryBean testFactoryBean() {
|
||||
return new TestFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EagerInitBean {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(value = "useThis", createIfMissing = true)
|
||||
private ExampleService service;
|
||||
|
||||
static ExampleService useThis() {
|
||||
return OVERRIDE_SERVICE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SingletonBean {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(beanName = "singleton",
|
||||
value = "useThis", createIfMissing = false)
|
||||
private String value;
|
||||
|
||||
static String useThis() {
|
||||
return "USED THIS";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestFactoryBean implements FactoryBean<Object> {
|
||||
|
||||
@Override
|
||||
public Object getObject() {
|
||||
return new SomeImplementation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class FactoryBeanRegisteringPostProcessor implements BeanFactoryPostProcessor, Ordered {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(TestFactoryBean.class);
|
||||
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition("test", beanDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EarlyBeanInitializationDetector implements BeanFactoryPostProcessor {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
Map<String, BeanWrapper> cache = (Map<String, BeanWrapper>) ReflectionTestUtils.getField(beanFactory,
|
||||
"factoryBeanInstanceCache");
|
||||
Assert.isTrue(cache.isEmpty(), "Early initialization of factory bean triggered.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface SomeInterface {
|
||||
|
||||
}
|
||||
|
||||
static class SomeImplementation implements SomeInterface {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.bean.override.example.ExampleBeanOverrideAnnotation;
|
||||
import org.springframework.test.bean.override.example.TestBeanOverrideMetaAnnotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||
import static org.springframework.test.bean.override.example.ExampleBeanOverrideProcessor.DUPLICATE_TRIGGER;
|
||||
|
||||
class BeanOverrideParserTests {
|
||||
|
||||
@Test
|
||||
void findsOnField() {
|
||||
BeanOverrideParser parser = new BeanOverrideParser();
|
||||
parser.parse(OnFieldConf.class);
|
||||
|
||||
assertThat(parser.getOverrideMetadata()).hasSize(1)
|
||||
.first()
|
||||
.extracting(om -> ((ExampleBeanOverrideAnnotation) om.overrideAnnotation()).value())
|
||||
.isEqualTo("onField");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowMultipleProcessorsOnDifferentElements() {
|
||||
BeanOverrideParser parser = new BeanOverrideParser();
|
||||
parser.parse(MultipleFieldsWithOnFieldConf.class);
|
||||
|
||||
assertThat(parser.getOverrideMetadata())
|
||||
.hasSize(2)
|
||||
.map(om -> ((ExampleBeanOverrideAnnotation) om.overrideAnnotation()).value())
|
||||
.containsOnly("onField1", "onField2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsMultipleAnnotationsOnSameElement() {
|
||||
BeanOverrideParser parser = new BeanOverrideParser();
|
||||
assertThatRuntimeException().isThrownBy(() -> parser.parse(MultipleOnFieldConf.class))
|
||||
.withMessage("Multiple bean override annotations found on annotated field <" +
|
||||
String.class.getName() + " " + MultipleOnFieldConf.class.getName() + ".message>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void detectsDuplicateMetadata() {
|
||||
BeanOverrideParser parser = new BeanOverrideParser();
|
||||
assertThatRuntimeException().isThrownBy(() -> parser.parse(DuplicateConf.class))
|
||||
.withMessage("Duplicate test overrideMetadata {DUPLICATE_TRIGGER}");
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class OnFieldConf {
|
||||
|
||||
@ExampleBeanOverrideAnnotation("onField")
|
||||
String message;
|
||||
|
||||
static String onField() {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleOnFieldConf {
|
||||
|
||||
@ExampleBeanOverrideAnnotation("foo")
|
||||
@TestBeanOverrideMetaAnnotation
|
||||
String message;
|
||||
|
||||
static String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleFieldsWithOnFieldConf {
|
||||
@ExampleBeanOverrideAnnotation("onField1")
|
||||
String message;
|
||||
|
||||
@ExampleBeanOverrideAnnotation("onField2")
|
||||
String messageOther;
|
||||
|
||||
static String onField1() {
|
||||
return "OK1";
|
||||
}
|
||||
|
||||
static String onField2() {
|
||||
return "OK2";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class DuplicateConf {
|
||||
|
||||
@ExampleBeanOverrideAnnotation(DUPLICATE_TRIGGER)
|
||||
String message1;
|
||||
|
||||
@ExampleBeanOverrideAnnotation(DUPLICATE_TRIGGER)
|
||||
String message2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OverrideMetadataTests {
|
||||
|
||||
static class ConcreteOverrideMetadata extends OverrideMetadata {
|
||||
|
||||
ConcreteOverrideMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride,
|
||||
BeanOverrideStrategy strategy) {
|
||||
super(field, overrideAnnotation, typeToOverride, strategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeanOverrideDescription() {
|
||||
return ConcreteOverrideMetadata.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, @Nullable Object existingBeanInstance) {
|
||||
return BeanOverrideStrategy.REPLACE_DEFINITION;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String annotated = "exampleField";
|
||||
|
||||
static OverrideMetadata exampleOverride() throws NoSuchFieldException {
|
||||
final Field annotated = OverrideMetadataTests.class.getField("annotated");
|
||||
return new ConcreteOverrideMetadata(Objects.requireNonNull(annotated), annotated.getAnnotation(NonNull.class),
|
||||
ResolvableType.forClass(String.class), BeanOverrideStrategy.REPLACE_DEFINITION);
|
||||
}
|
||||
|
||||
@Test
|
||||
void implicitConfigurations() throws NoSuchFieldException {
|
||||
final OverrideMetadata metadata = exampleOverride();
|
||||
assertThat(metadata.getExpectedBeanName()).as("expectedBeanName")
|
||||
.isEqualTo(metadata.field().getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.convention;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.bean.override.example.ExampleService;
|
||||
import org.springframework.test.bean.override.example.FailingExampleService;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
class TestBeanOverrideProcessorTests {
|
||||
|
||||
@Test
|
||||
void ensureMethodFindsFromList() {
|
||||
Method m = TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class,
|
||||
"example1", "example2", "example3");
|
||||
|
||||
assertThat(m.getName()).isEqualTo("example2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ensureMethodNotFound() {
|
||||
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(
|
||||
MethodConventionConf.class, ExampleService.class, "example1", "example3"))
|
||||
.withMessage("Found 0 static methods instead of exactly one, matching a name in [example1, example3] with return type " +
|
||||
ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName())
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ensureMethodTwoFound() {
|
||||
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(
|
||||
MethodConventionConf.class, ExampleService.class, "example2", "example4"))
|
||||
.withMessage("Found 2 static methods instead of exactly one, matching a name in [example2, example4] with return type " +
|
||||
ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName())
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ensureMethodNoNameProvided() {
|
||||
assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(
|
||||
MethodConventionConf.class, ExampleService.class))
|
||||
.withMessage("At least one expectedMethodName is required")
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMetaDataForUnknownExplicitMethod() throws NoSuchFieldException {
|
||||
Field f = ExplicitMethodNameConf.class.getField("a");
|
||||
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class));
|
||||
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
|
||||
assertThatException().isThrownBy(() -> processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
|
||||
.withMessage("Found 0 static methods instead of exactly one, matching a name in [explicit1] with return type " +
|
||||
ExampleService.class.getName() + " on class " + ExplicitMethodNameConf.class.getName())
|
||||
.isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMetaDataForKnownExplicitMethod() throws NoSuchFieldException {
|
||||
Field f = ExplicitMethodNameConf.class.getField("b");
|
||||
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class));
|
||||
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
|
||||
assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
|
||||
.isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMetaDataWithDeferredEnsureMethodCheck() throws NoSuchFieldException {
|
||||
Field f = MethodConventionConf.class.getField("field");
|
||||
final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class));
|
||||
TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor();
|
||||
assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class)))
|
||||
.isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class);
|
||||
}
|
||||
|
||||
static class MethodConventionConf {
|
||||
|
||||
@TestBean
|
||||
public ExampleService field;
|
||||
|
||||
@Bean
|
||||
ExampleService example1() {
|
||||
return new FailingExampleService();
|
||||
}
|
||||
|
||||
static ExampleService example2() {
|
||||
return new FailingExampleService();
|
||||
}
|
||||
|
||||
public static ExampleService example4() {
|
||||
return new FailingExampleService();
|
||||
}
|
||||
}
|
||||
|
||||
static class ExplicitMethodNameConf {
|
||||
|
||||
@TestBean(methodName = "explicit1")
|
||||
public ExampleService a;
|
||||
|
||||
@TestBean(methodName = "explicit2")
|
||||
public ExampleService b;
|
||||
|
||||
static ExampleService explicit2() {
|
||||
return new FailingExampleService();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.test.bean.override.BeanOverride;
|
||||
|
||||
@BeanOverride(ExampleBeanOverrideProcessor.class)
|
||||
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExampleBeanOverrideAnnotation {
|
||||
|
||||
static final String DEFAULT_VALUE = "TEST OVERRIDE";
|
||||
|
||||
String value() default DEFAULT_VALUE;
|
||||
|
||||
boolean createIfMissing() default false;
|
||||
|
||||
String beanName() default "";
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.test.bean.override.BeanOverrideProcessor;
|
||||
import org.springframework.test.bean.override.OverrideMetadata;
|
||||
|
||||
public class ExampleBeanOverrideProcessor implements BeanOverrideProcessor {
|
||||
|
||||
public ExampleBeanOverrideProcessor() {
|
||||
}
|
||||
|
||||
private static final TestOverrideMetadata CONSTANT = new TestOverrideMetadata() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{DUPLICATE_TRIGGER}";
|
||||
}
|
||||
};
|
||||
public static final String DUPLICATE_TRIGGER = "CONSTANT";
|
||||
|
||||
@Override
|
||||
public OverrideMetadata createMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride) {
|
||||
if (!(overrideAnnotation instanceof ExampleBeanOverrideAnnotation annotation)) {
|
||||
throw new IllegalStateException("unexpected annotation");
|
||||
}
|
||||
if (annotation.value().equals(DUPLICATE_TRIGGER)) {
|
||||
return CONSTANT;
|
||||
}
|
||||
return new TestOverrideMetadata(field, annotation, typeToOverride);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
/**
|
||||
* Example service interface for mocking tests.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public interface ExampleService {
|
||||
|
||||
String greeting();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* An {@link ExampleService} that always throws an exception.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Service
|
||||
public class FailingExampleService implements ExampleService {
|
||||
|
||||
@Override
|
||||
public String greeting() {
|
||||
throw new IllegalStateException("Failed");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
/**
|
||||
* Example service implementation for spy tests.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class RealExampleService implements ExampleService {
|
||||
|
||||
private final String greeting;
|
||||
|
||||
public RealExampleService(String greeting) {
|
||||
this.greeting = greeting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String greeting() {
|
||||
return this.greeting;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ExampleBeanOverrideAnnotation("foo")
|
||||
public @interface TestBeanOverrideMetaAnnotation { }
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.bean.override.BeanOverrideStrategy;
|
||||
import org.springframework.test.bean.override.OverrideMetadata;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.test.bean.override.example.ExampleBeanOverrideAnnotation.DEFAULT_VALUE;
|
||||
|
||||
public class TestOverrideMetadata extends OverrideMetadata {
|
||||
|
||||
@Nullable
|
||||
private final Method method;
|
||||
|
||||
@Nullable
|
||||
private final String beanName;
|
||||
|
||||
@Nullable
|
||||
private static Method findMethod(AnnotatedElement element, String methodName) {
|
||||
if (DEFAULT_VALUE.equals(methodName)) {
|
||||
return null;
|
||||
}
|
||||
if (element instanceof Field f) {
|
||||
for (Method m : f.getDeclaringClass().getDeclaredMethods()) {
|
||||
if (!Modifier.isStatic(m.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (m.getName().equals(methodName)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Expected a static method named <" + methodName + "> alongside annotated field <" + f.getName() + ">");
|
||||
}
|
||||
if (element instanceof Method m) {
|
||||
if (m.getName().equals(methodName) && Modifier.isStatic(m.getModifiers())) {
|
||||
return m;
|
||||
}
|
||||
throw new IllegalStateException("Expected the annotated method to be static and named <" + methodName + ">");
|
||||
}
|
||||
if (element instanceof Class c) {
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
if (!Modifier.isStatic(m.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (m.getName().equals(methodName)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Expected a static method named <" + methodName + "> on annotated class <" + c.getSimpleName() + ">");
|
||||
}
|
||||
throw new IllegalStateException("Expected the annotated element to be a Field, Method or Class");
|
||||
}
|
||||
|
||||
public TestOverrideMetadata(Field field, ExampleBeanOverrideAnnotation overrideAnnotation, ResolvableType typeToOverride) {
|
||||
super(field, overrideAnnotation, typeToOverride, overrideAnnotation.createIfMissing() ?
|
||||
BeanOverrideStrategy.REPLACE_OR_CREATE_DEFINITION: BeanOverrideStrategy.REPLACE_DEFINITION);
|
||||
this.method = findMethod(field, overrideAnnotation.value());
|
||||
this.beanName = overrideAnnotation.beanName();
|
||||
}
|
||||
|
||||
//Used to trigger duplicate detection in parser test
|
||||
TestOverrideMetadata() {
|
||||
super(null, null, null, null);
|
||||
this.method = null;
|
||||
this.beanName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getExpectedBeanName() {
|
||||
if (StringUtils.hasText(this.beanName)) {
|
||||
return this.beanName;
|
||||
}
|
||||
return super.getExpectedBeanName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBeanOverrideDescription() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, @Nullable Object existingBeanInstance) {
|
||||
if (this.method == null) {
|
||||
return DEFAULT_VALUE;
|
||||
}
|
||||
try {
|
||||
this.method.setAccessible(true);
|
||||
return this.method.invoke(null);
|
||||
}
|
||||
catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Example components for testing spring-test Bean overriding feature.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.test.bean.override.example;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -25,6 +25,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.test.bean.override.BeanOverrideTestExecutionListener;
|
||||
import org.springframework.test.bean.override.mockito.MockitoResetTestExecutionListener;
|
||||
import org.springframework.test.bean.override.mockito.MockitoTestExecutionListener;
|
||||
import org.springframework.test.context.event.ApplicationEventsTestExecutionListener;
|
||||
import org.springframework.test.context.event.EventPublishingTestExecutionListener;
|
||||
import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener;
|
||||
@@ -65,12 +68,15 @@ class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,//
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,//
|
||||
ApplicationEventsTestExecutionListener.class,//
|
||||
MockitoTestExecutionListener.class,//
|
||||
DependencyInjectionTestExecutionListener.class,//
|
||||
micrometerListenerClass,//
|
||||
DirtiesContextTestExecutionListener.class,//
|
||||
TransactionalTestExecutionListener.class,//
|
||||
SqlScriptsTestExecutionListener.class,//
|
||||
EventPublishingTestExecutionListener.class
|
||||
EventPublishingTestExecutionListener.class,//
|
||||
MockitoResetTestExecutionListener.class,//
|
||||
BeanOverrideTestExecutionListener.class
|
||||
);
|
||||
assertRegisteredListeners(DefaultListenersTestCase.class, expected);
|
||||
}
|
||||
@@ -84,12 +90,15 @@ class TestExecutionListenersTests {
|
||||
ServletTestExecutionListener.class,//
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,//
|
||||
ApplicationEventsTestExecutionListener.class,//
|
||||
MockitoTestExecutionListener.class,//
|
||||
DependencyInjectionTestExecutionListener.class,//
|
||||
micrometerListenerClass,//
|
||||
DirtiesContextTestExecutionListener.class,//
|
||||
TransactionalTestExecutionListener.class,//
|
||||
SqlScriptsTestExecutionListener.class,//
|
||||
EventPublishingTestExecutionListener.class
|
||||
EventPublishingTestExecutionListener.class,//
|
||||
MockitoResetTestExecutionListener.class,//
|
||||
BeanOverrideTestExecutionListener.class
|
||||
);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerPrependedTestCase.class, expected);
|
||||
}
|
||||
@@ -102,12 +111,15 @@ class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,//
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,//
|
||||
ApplicationEventsTestExecutionListener.class,//
|
||||
MockitoTestExecutionListener.class,//
|
||||
DependencyInjectionTestExecutionListener.class,//
|
||||
micrometerListenerClass,//
|
||||
DirtiesContextTestExecutionListener.class,//
|
||||
TransactionalTestExecutionListener.class,
|
||||
SqlScriptsTestExecutionListener.class,//
|
||||
EventPublishingTestExecutionListener.class,//
|
||||
MockitoResetTestExecutionListener.class,//
|
||||
BeanOverrideTestExecutionListener.class,//
|
||||
BazTestExecutionListener.class
|
||||
);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerAppendedTestCase.class, expected);
|
||||
@@ -121,13 +133,16 @@ class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,//
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,//
|
||||
ApplicationEventsTestExecutionListener.class,//
|
||||
MockitoTestExecutionListener.class,//
|
||||
DependencyInjectionTestExecutionListener.class,//
|
||||
BarTestExecutionListener.class,//
|
||||
micrometerListenerClass,//
|
||||
DirtiesContextTestExecutionListener.class,//
|
||||
TransactionalTestExecutionListener.class,//
|
||||
SqlScriptsTestExecutionListener.class,//
|
||||
EventPublishingTestExecutionListener.class
|
||||
EventPublishingTestExecutionListener.class,//
|
||||
MockitoResetTestExecutionListener.class,//
|
||||
BeanOverrideTestExecutionListener.class
|
||||
);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerInsertedTestCase.class, expected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user