Support declarative ContextCustomizerFactory registration in the TCF

Prior to this commit, it was only possible to register a
ContextCustomizerFactory in the TestContext framework (TCF) via the
SpringFactoriesLoader mechanism.

This commit introduces support for declarative registration of a
ContextCustomizerFactory local to a test class via a new
@ContextCustomizerFactories annotation.

Closes gh-26148
This commit is contained in:
Sam Brannen
2023-06-30 13:29:12 +02:00
parent 99a50e7cea
commit a220c545fc
27 changed files with 1085 additions and 70 deletions

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.util.List;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
/**
* @author Sam Brannen
* @since 6.1
*/
class BarContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> context.getBeanFactory().registerSingleton("bar", "baz");
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactories;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test which verifies support for {@link ContextCustomizerFactory}
* and {@link ContextCustomizer} when a custom factory is registered declaratively
* via {@link ContextCustomizerFactories @ContextCustomizerFactories}.
*
* @author Sam Brannen
* @since 6.1
*/
@SpringJUnitConfig({})
@CustomizeWithFruit
@CustomizeWithFoo
@CustomizeWithBar
class ContextCustomizerDeclarativeRegistrationComposedAnnotationTests {
// GlobalFruitContextCustomizerFactory is registered via spring.factories
@Autowired(required = false)
@Qualifier("global$fruit")
String fruit;
@Autowired(required = false)
@Qualifier("foo")
String foo;
@Autowired(required = false)
@Qualifier("bar")
String bar;
@Test
void injectedBean() {
// registered globally via spring.factories
assertThat(fruit).isEqualTo("apple, banana, cherry");
// From local @ContextCustomizerFactories
assertThat(foo).isEqualTo("bar");
// @ContextCustomizerFactories is not currently supported as a repeatable annotation.
assertThat(bar).isNull();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactories;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test which verifies support for {@link ContextCustomizerFactory}
* and {@link ContextCustomizer} when a custom factory is registered declaratively
* via {@link ContextCustomizerFactories @ContextCustomizerFactories}.
*
* @author Sam Brannen
* @since 6.1
*/
@SpringJUnitConfig({})
@CustomizeWithFruit
@CustomizeWithFoo
@ContextCustomizerFactories(EnigmaContextCustomizerFactory.class)
@CustomizeWithBar
class ContextCustomizerDeclarativeRegistrationTests {
// GlobalFruitContextCustomizerFactory is registered via spring.factories
@Autowired(required = false)
@Qualifier("global$fruit")
String fruit;
@Autowired
Integer enigma;
@Autowired(required = false)
@Qualifier("foo")
String foo;
@Autowired(required = false)
@Qualifier("bar")
String bar;
@Test
void injectedBean() {
// registered globally via spring.factories
assertThat(fruit).isEqualTo("apple, banana, cherry");
// From local @ContextCustomizerFactories
assertThat(enigma).isEqualTo(42);
// @ContextCustomizerFactories is not currently supported as a repeatable annotation,
// and a directly present @ContextCustomizerFactories annotation overrides
// @ContextCustomizerFactories meta-annotations.
assertThat(foo).isNull();
assertThat(bar).isNull();
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.BootstrapWith;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactories;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.customizers.ContextCustomizerTests.EnigmaTestContextBootstrapper;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.context.support.AbstractTestContextBootstrapper;
import org.springframework.test.context.support.DefaultTestContextBootstrapper;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test which verifies support for {@link ContextCustomizerFactory}
* and {@link ContextCustomizer} when a custom factory is registered by overriding
* {@link AbstractTestContextBootstrapper#getContextCustomizerFactories} and
* additional factories are registered declaratively via
* {@link ContextCustomizerFactories @ContextCustomizerFactories}.
*
* @author Sam Brannen
* @author Phillip Webb
* @since 4.3
*/
@SpringJUnitConfig({})
@CustomizeWithFoo
@BootstrapWith(EnigmaTestContextBootstrapper.class)
@CustomizeWithBar
class ContextCustomizerTests {
// GlobalFruitContextCustomizerFactory is registered via spring.factories
@Autowired(required = false)
@Qualifier("global$fruit")
String fruit;
@Autowired
Integer enigma;
@Autowired(required = false)
@Qualifier("foo")
String foo;
@Autowired(required = false)
@Qualifier("bar")
String bar;
@Test
void injectedBean() {
// Local Bootstrapper overrides spring.factories lookup
assertThat(fruit).isNull();
// From local Bootstrapper
assertThat(enigma).isEqualTo(42);
// From local @ContextCustomizerFactories
assertThat(foo).isEqualTo("bar");
// @ContextCustomizerFactories is not currently supported as a repeatable annotation.
assertThat(bar).isNull();
}
static class EnigmaTestContextBootstrapper extends DefaultTestContextBootstrapper {
@Override
protected List<ContextCustomizerFactory> getContextCustomizerFactories() {
return List.of(new EnigmaContextCustomizerFactory());
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.test.context.ContextCustomizerFactories;
/**
* @author Sam Brannen
* @since 6.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ContextCustomizerFactories(BarContextCustomizerFactory.class)
@interface CustomizeWithBar {
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.test.context.ContextCustomizerFactories;
/**
* @author Sam Brannen
* @since 6.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ContextCustomizerFactories(FooContextCustomizerFactory.class)
@interface CustomizeWithFoo {
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marker annotation to trigger {@link GlobalFruitContextCustomizerFactory}.
*
* @author Sam Brannen
* @since 6.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@interface CustomizeWithFruit {
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.util.List;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
/**
* @author Sam Brannen
* @since 6.1
*/
class EnigmaContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> context.getBeanFactory().registerSingleton("enigma", 42);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.util.List;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
/**
* @author Sam Brannen
* @since 6.1
*/
class FooContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> context.getBeanFactory().registerSingleton("foo", "bar");
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2023 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.context.customizers;
import java.util.List;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.MergedContextConfiguration;
/**
* @author Sam Brannen
* @since 6.1
*/
class GlobalFruitContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
if (testClass.isAnnotationPresent(CustomizeWithFruit.class)) {
return new GlobalFruitContextCustomizer();
}
return null;
}
}
class GlobalFruitContextCustomizer implements ContextCustomizer {
@Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
// Use "global$fruit" as the bean name instead of something simple like "fruit"
// to avoid bean name clashes with any test that registers a bean named "fruit".
context.getBeanFactory().registerSingleton("global$fruit", "apple, banana, cherry");
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other != null && getClass() == other.getClass()));
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Sam Brannen
* @since 6.1
*/
@CustomizeWithBar
class InheritedContextCustomizerRegistrationTests extends LocalContextCustomizerRegistrationTests {
@Autowired
@Qualifier("bar")
String bar;
@Override
@Test
void injectedBean() {
assertThat(fruit).isEqualTo("apple, banana, cherry");
assertThat(foo).isEqualTo("bar");
assertThat(bar).isEqualTo("baz");
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Sam Brannen
* @since 6.1
*/
@SpringJUnitConfig({})
@CustomizeWithFruit
@CustomizeWithFoo
class LocalContextCustomizerRegistrationTests {
// GlobalFruitContextCustomizerFactory is registered via spring.factories
@Autowired(required = false)
@Qualifier("global$fruit")
String fruit;
@Autowired(required = false)
@Qualifier("foo")
String foo;
@Test
void injectedBean() {
assertThat(fruit).isEqualTo("apple, banana, cherry");
assertThat(foo).isEqualTo("bar");
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextCustomizerFactories;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Sam Brannen
* @since 6.1
*/
@ContextCustomizerFactories(factories = {BarContextCustomizerFactory.class, EnigmaContextCustomizerFactory.class},
inheritFactories = false)
class OverriddenContextCustomizerRegistrationTests extends LocalContextCustomizerRegistrationTests {
@Autowired
@Qualifier("bar")
String bar;
@Autowired
Integer enigma;
@Override
@Test
void injectedBean() {
// globally registered via spring.factories
assertThat(fruit).isEqualTo("apple, banana, cherry");
// Overridden by this subclass (inheritFactories = false)
assertThat(foo).isNull();
// Local to this subclass
assertThat(bar).isEqualTo("baz");
assertThat(enigma).isEqualTo(42);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2023 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.context.customizers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextCustomizerFactories;
import org.springframework.test.context.ContextCustomizerFactories.MergeMode;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Sam Brannen
* @since 6.1
*/
@SpringJUnitConfig({})
@ContextCustomizerFactories(factories = {FooContextCustomizerFactory.class, BarContextCustomizerFactory.class},
mergeMode = MergeMode.REPLACE_DEFAULTS)
class ReplaceDefaultsContextCustomizerTests {
// GlobalFruitContextCustomizerFactory is registered via spring.factories
@Autowired(required = false)
@Qualifier("global$fruit")
String fruit;
@Autowired(required = false)
@Qualifier("foo")
String foo;
@Autowired(required = false)
@Qualifier("bar")
String bar;
@Test
void injectedBean() {
// MergeMode.REPLACE_DEFAULTS overrides spring.factories lookup
assertThat(fruit).isNull();
// From local @ContextCustomizerFactories
assertThat(foo).isEqualTo("bar");
assertThat(bar).isEqualTo("baz");
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2002-2019 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.context.junit4;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.BootstrapWith;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.junit4.ContextCustomizerSpringRunnerTests.CustomTestContextBootstrapper;
import org.springframework.test.context.support.DefaultTestContextBootstrapper;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
/**
* JUnit 4 based integration test which verifies support of
* {@link ContextCustomizerFactory} and {@link ContextCustomizer}.
*
* @author Sam Brannen
* @author Phillip Webb
* @since 4.3
*/
@RunWith(SpringRunner.class)
@BootstrapWith(CustomTestContextBootstrapper.class)
public class ContextCustomizerSpringRunnerTests {
@Autowired String foo;
@Test
public void injectedBean() {
assertThat(foo).isEqualTo("foo");
}
static class CustomTestContextBootstrapper extends DefaultTestContextBootstrapper {
@Override
protected List<ContextCustomizerFactory> getContextCustomizerFactories() {
return singletonList(
(ContextCustomizerFactory) (testClass, configAttributes) ->
(ContextCustomizer) (context, mergedConfig) -> context.getBeanFactory().registerSingleton("foo", "foo")
);
}
}
}