Honor spring.autoconfigure.exclude in test slices

Previously, the import selector for `@ImportAutoConfiguration` did not
consider the spring.autoconfigure.exclude property when determining
which auto-configurations to exclude. This meant that tests using a
slice that included a particular auto-configuration would include it
even if the application's configuration excluded it via
spring.autoconfigure.exclude. Confusingly, this could result in a
sliced test using an auto-configuration that would be excluded in a
broader `@SpringBootTest`.

This commit updates the ImportAutoConfigurationImportSelector to
consider the spring.autoconfigure.exclude property so that sliced tests
will use a subset of the auto-configurations that a `@SpringBootTest`
would use.

Fixes gh-21736
pull/22996/head
Andy Wilkinson 4 years ago
parent 1b85ce0769
commit 502ccb6586

@ -233,13 +233,23 @@ public class AutoConfigurationImportSelector implements DeferredImportSelector,
return excluded; return excluded;
} }
private List<String> getExcludeAutoConfigurationsProperty() { /**
if (getEnvironment() instanceof ConfigurableEnvironment) { * Returns the auto-configurations excluded by the
Binder binder = Binder.get(getEnvironment()); * {@code spring.autoconfigure.exclude} property.
* @return excluded auto-configurations
* @since 2.3.2
*/
protected List<String> getExcludeAutoConfigurationsProperty() {
Environment environment = getEnvironment();
if (environment == null) {
return Collections.emptyList();
}
if (environment instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(environment);
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList) return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList()); .orElse(Collections.emptyList());
} }
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class); String[] excludes = environment.getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList(); return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -118,6 +118,7 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
} }
} }
} }
exclusions.addAll(getExcludeAutoConfigurationsProperty());
return exclusions; return exclusions;
} }

@ -25,22 +25,19 @@ import java.util.Set;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
import org.springframework.core.env.Environment;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verifyNoInteractions;
/** /**
* Tests for {@link ImportAutoConfigurationImportSelector}. * Tests for {@link ImportAutoConfigurationImportSelector}.
@ -54,12 +51,10 @@ class ImportAutoConfigurationImportSelectorTests {
private final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory(); private final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Mock private final MockEnvironment environment = new MockEnvironment();
private Environment environment;
@BeforeEach @BeforeEach
void setup() { void setup() {
MockitoAnnotations.initMocks(this);
this.importSelector.setBeanFactory(this.beanFactory); this.importSelector.setBeanFactory(this.beanFactory);
this.importSelector.setEnvironment(this.environment); this.importSelector.setEnvironment(this.environment);
this.importSelector.setResourceLoader(new DefaultResourceLoader()); this.importSelector.setResourceLoader(new DefaultResourceLoader());
@ -80,10 +75,11 @@ class ImportAutoConfigurationImportSelectorTests {
} }
@Test @Test
void propertyExclusionsAreNotApplied() throws Exception { void propertyExclusionsAreApplied() throws IOException {
AnnotationMetadata annotationMetadata = getAnnotationMetadata(ImportFreeMarker.class); this.environment.setProperty("spring.autoconfigure.exclude", FreeMarkerAutoConfiguration.class.getName());
this.importSelector.selectImports(annotationMetadata); AnnotationMetadata annotationMetadata = getAnnotationMetadata(MultipleImports.class);
verifyNoInteractions(this.environment); String[] imports = this.importSelector.selectImports(annotationMetadata);
assertThat(imports).containsExactly(ThymeleafAutoConfiguration.class.getName());
} }
@Test @Test
@ -288,7 +284,9 @@ class ImportAutoConfigurationImportSelectorTests {
@interface MetaImportAutoConfiguration { @interface MetaImportAutoConfiguration {
@AliasFor(annotation = ImportAutoConfiguration.class) @AliasFor(annotation = ImportAutoConfiguration.class)
Class<?>[] exclude() default {}; Class<?>[] exclude() default {
};
} }
@ -308,7 +306,9 @@ class ImportAutoConfigurationImportSelectorTests {
@interface SelfAnnotating { @interface SelfAnnotating {
@AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude") @AliasFor(annotation = ImportAutoConfiguration.class, attribute = "exclude")
Class<?>[] excludeAutoConfiguration() default {}; Class<?>[] excludeAutoConfiguration() default {
};
} }

Loading…
Cancel
Save