Allow default CacheAwareContextLoaderDelegate configuration via system property

Prior to this commit, the default CacheAwareContextLoaderDelegate could
be configured by extending AbstractTestContextBootstrapper and
overriding getCacheAwareContextLoaderDelegate(); however, this required
that the user configure the custom TestContextBootstrapper via
@BootstrapWith.

This commit introduces a new
"spring.test.context.default.CacheAwareContextLoaderDelegate" property
that can be configured via a JVM system property or via the
SpringProperties mechanism. BootstrapUtils uses this new property to
load the default CacheAwareContextLoaderDelegate. If the property is
not defined, BootstrapUtils will fall back to creating a
DefaultCacheAwareContextLoaderDelegate as it did previously.

This allows third parties to configure the default
CacheAwareContextLoaderDelegate transparently for the user -- for
example, to intercept context loading in order to load the context in a
different manner -- for example, to make use of ahead of time (AOT)
techniques for implementing a different type of ApplicationContext at
build time.

Closes gh-27540
This commit is contained in:
Sam Brannen
2021-10-10 22:40:26 +02:00
parent e8f6cd10a5
commit 63fac1b7c8
3 changed files with 127 additions and 10 deletions

View File

@@ -0,0 +1,95 @@
/*
* Copyright 2002-2021 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.support;
import org.junit.jupiter.api.Test;
import org.junit.platform.testkit.engine.EngineTestKit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.SpringProperties;
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
/**
* Integration tests for configuring a custom default {@link CacheAwareContextLoaderDelegate}
* via {@link SpringProperties}.
*
* @author sbrannen
* @since 5.3.11
*/
class CustomDefaultCacheAwareContextLoaderDelegateTests {
@Test
void customDefaultCacheAwareContextLoaderDelegateConfiguredViaSpringProperties() {
String key = CacheAwareContextLoaderDelegate.DEFAULT_CACHE_AWARE_CONTEXT_LOADER_DELEGATE_PROPERTY_NAME;
try {
SpringProperties.setProperty(key, AotCacheAwareContextLoaderDelegate.class.getName());
EngineTestKit.engine("junit-jupiter")//
.selectors(selectClass(TestCase.class))//
.execute()//
.testEvents()//
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
}
finally {
SpringProperties.setProperty(key, null);
}
}
@SpringJUnitConfig
static class TestCase {
@Test
void test(@Autowired String foo) {
// foo will be "bar" unless the AotCacheAwareContextLoaderDelegate is registered.
assertThat(foo).isEqualTo("AOT");
}
@Configuration
static class Config {
@Bean
String foo() {
return "bar";
}
}
}
static class AotCacheAwareContextLoaderDelegate extends DefaultCacheAwareContextLoaderDelegate {
@Override
protected ApplicationContext loadContextInternal(MergedContextConfiguration mergedContextConfiguration) {
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.registerBean("foo", String.class, () -> "AOT");
applicationContext.refresh();
return applicationContext;
}
}
}