Revise logging in the TestContext framework

For a Spring Boot test, Logback logs at DEBUG level by default until
Spring Boot's logging infrastructure has a chance to take control, and
this can result in a considerable amount of INFO and DEBUG output.

It's not the number of lines that causes an issue. Rather, it's the
amount of information in each line that can become overwhelming,
especially when the MergedContextConfiguration is complex.

The main reason for lengthy DEBUG logging in a Spring Boot test is that
Spring Boot's ImportsContextCustomizer implements toString() which
results in logging of the fully qualified class names of all imported
configuration classes. In an example using @WebMvcTest, this resulted
in logging of 27 imported classes twice. However, the lists of
registered TestExecutionListener, ContextCustomizerFactory, and
ContextCustomizer implementations are also logged separately, and that
adds quite a bit of noise at DEBUG level.

This commit addresses these issues and simultaneously completely
revises logging within the Spring TestContext Framework (TCF).

- Numerous log statements are now logged at TRACE level instead of
  DEBUG.

- Numerous log statements now have two modes. When logging at TRACE
  level, fully qualified class names (or the results of invoking
  toString() on related components) are included. When logging at DEBUG
  level, simple names of classes are logged and the results of invoking
  toString() on related components are omitted.

- toString() implementations in TCF components are now based on the
  newly introduced SimpleValueStyler for ToStringCreator.

The combination of the above changes greatly reduces the amount of
DEBUG logging output in the TCF, but users can still access complete
details by switching to TRACE level logging.

Closes gh-29229
This commit is contained in:
Sam Brannen 2022-10-25 13:57:47 +02:00
parent f16366e161
commit 997dd3ee65
32 changed files with 335 additions and 195 deletions

View File

@ -82,7 +82,7 @@ public abstract class BootstrapUtils {
ClassUtils.forName(className, BootstrapUtils.class.getClassLoader()); ClassUtils.forName(className, BootstrapUtils.class.getClassLoader());
Constructor<? extends BootstrapContext> constructor = Constructor<? extends BootstrapContext> constructor =
clazz.getConstructor(Class.class, CacheAwareContextLoaderDelegate.class); clazz.getConstructor(Class.class, CacheAwareContextLoaderDelegate.class);
logger.debug(LogMessage.format("Instantiating BootstrapContext using constructor [%s]", constructor)); logger.trace(LogMessage.format("Instantiating BootstrapContext using constructor [%s]", constructor));
return BeanUtils.instantiateClass(constructor, testClass, cacheAwareContextLoaderDelegate); return BeanUtils.instantiateClass(constructor, testClass, cacheAwareContextLoaderDelegate);
} }
catch (Throwable ex) { catch (Throwable ex) {
@ -97,7 +97,7 @@ public abstract class BootstrapUtils {
try { try {
clazz = (Class<? extends CacheAwareContextLoaderDelegate>) clazz = (Class<? extends CacheAwareContextLoaderDelegate>)
ClassUtils.forName(className, BootstrapUtils.class.getClassLoader()); ClassUtils.forName(className, BootstrapUtils.class.getClassLoader());
logger.debug(LogMessage.format("Instantiating CacheAwareContextLoaderDelegate from class [%s]", className)); logger.trace(LogMessage.format("Instantiating CacheAwareContextLoaderDelegate from class [%s]", className));
return BeanUtils.instantiateClass(clazz, CacheAwareContextLoaderDelegate.class); return BeanUtils.instantiateClass(clazz, CacheAwareContextLoaderDelegate.class);
} }
catch (Throwable ex) { catch (Throwable ex) {
@ -151,7 +151,7 @@ public abstract class BootstrapUtils {
if (clazz == null) { if (clazz == null) {
clazz = resolveDefaultTestContextBootstrapper(testClass); clazz = resolveDefaultTestContextBootstrapper(testClass);
} }
logger.debug(LogMessage.format("Instantiating TestContextBootstrapper for test class [%s] from class [%s]", logger.trace(LogMessage.format("Instantiating TestContextBootstrapper for test class [%s] from class [%s]",
testClass.getName(), clazz.getName())); testClass.getName(), clazz.getName()));
TestContextBootstrapper testContextBootstrapper = TestContextBootstrapper testContextBootstrapper =
BeanUtils.instantiateClass(clazz, TestContextBootstrapper.class); BeanUtils.instantiateClass(clazz, TestContextBootstrapper.class);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 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.
@ -23,6 +23,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -368,15 +370,15 @@ public class ContextConfigurationAttributes {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("declaringClass", this.declaringClass.getName()) .append("declaringClass", this.declaringClass)
.append("classes", ObjectUtils.nullSafeToString(this.classes)) .append("classes", this.classes)
.append("locations", ObjectUtils.nullSafeToString(this.locations)) .append("locations", this.locations)
.append("inheritLocations", this.inheritLocations) .append("inheritLocations", this.inheritLocations)
.append("initializers", ObjectUtils.nullSafeToString(this.initializers)) .append("initializers", this.initializers)
.append("inheritInitializers", this.inheritInitializers) .append("inheritInitializers", this.inheritInitializers)
.append("name", this.name) .append("name", this.name)
.append("contextLoaderClass", this.contextLoaderClass.getName()) .append("contextLoaderClass", this.contextLoaderClass)
.toString(); .toString();
} }

View File

@ -24,6 +24,8 @@ import java.util.Set;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -495,16 +497,16 @@ public class MergedContextConfiguration implements Serializable {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("testClass", this.testClass) .append("testClass", this.testClass)
.append("locations", ObjectUtils.nullSafeToString(this.locations)) .append("locations", this.locations)
.append("classes", ObjectUtils.nullSafeToString(this.classes)) .append("classes", this.classes)
.append("contextInitializerClasses", ObjectUtils.nullSafeToString(this.contextInitializerClasses)) .append("contextInitializerClasses", this.contextInitializerClasses)
.append("activeProfiles", ObjectUtils.nullSafeToString(this.activeProfiles)) .append("activeProfiles", this.activeProfiles)
.append("propertySourceLocations", ObjectUtils.nullSafeToString(this.propertySourceLocations)) .append("propertySourceLocations", this.propertySourceLocations)
.append("propertySourceProperties", ObjectUtils.nullSafeToString(this.propertySourceProperties)) .append("propertySourceProperties", this.propertySourceProperties)
.append("contextCustomizers", this.contextCustomizers) .append("contextCustomizers", this.contextCustomizers)
.append("contextLoader", nullSafeClassName(this.contextLoader)) .append("contextLoader", (this.contextLoader != null ? this.contextLoader.getClass() : null))
.append("parent", this.parent) .append("parent", this.parent)
.toString(); .toString();
} }

View File

@ -31,6 +31,8 @@ import org.springframework.core.annotation.MergedAnnotationPredicates;
import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.core.annotation.RepeatableContainers; import org.springframework.core.annotation.RepeatableContainers;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration; import org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration;
@ -585,9 +587,9 @@ public abstract class TestContextAnnotationUtils {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("rootDeclaringClass", this.rootDeclaringClass.getName()) .append("rootDeclaringClass", this.rootDeclaringClass)
.append("declaringClass", this.declaringClass.getName()) .append("declaringClass", this.declaringClass)
.append("annotation", this.annotation) .append("annotation", this.annotation)
.toString(); .toString();
} }

View File

@ -123,7 +123,7 @@ class AotTestContextInitializersCodeGenerator {
code.addStatement("$T map = new $T<>()", CONTEXT_INITIALIZER_SUPPLIER_MAP, HashMap.class); code.addStatement("$T map = new $T<>()", CONTEXT_INITIALIZER_SUPPLIER_MAP, HashMap.class);
this.initializerClassMappings.forEach((className, testClasses) -> { this.initializerClassMappings.forEach((className, testClasses) -> {
List<String> testClassNames = testClasses.stream().map(Class::getName).toList(); List<String> testClassNames = testClasses.stream().map(Class::getName).toList();
logger.debug(LogMessage.format( logger.trace(LogMessage.format(
"Generating mapping from AOT context initializer supplier [%s] to test classes %s", "Generating mapping from AOT context initializer supplier [%s] to test classes %s",
className.reflectionName(), testClassNames)); className.reflectionName(), testClassNames));
testClassNames.forEach(testClassName -> testClassNames.forEach(testClassName ->
@ -146,7 +146,7 @@ class AotTestContextInitializersCodeGenerator {
code.addStatement("$T map = new $T<>()", CONTEXT_INITIALIZER_CLASS_MAP, HashMap.class); code.addStatement("$T map = new $T<>()", CONTEXT_INITIALIZER_CLASS_MAP, HashMap.class);
this.initializerClassMappings.forEach((className, testClasses) -> { this.initializerClassMappings.forEach((className, testClasses) -> {
List<String> testClassNames = testClasses.stream().map(Class::getName).toList(); List<String> testClassNames = testClasses.stream().map(Class::getName).toList();
logger.debug(LogMessage.format( logger.trace(LogMessage.format(
"Generating mapping from AOT context initializer class [%s] to test classes %s", "Generating mapping from AOT context initializer class [%s] to test classes %s",
className.reflectionName(), testClassNames)); className.reflectionName(), testClassNames));
testClassNames.forEach(testClassName -> testClassNames.forEach(testClassName ->

View File

@ -19,6 +19,8 @@ package org.springframework.test.context.cache;
import java.util.Collections; import java.util.Collections;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.CacheAwareContextLoaderDelegate; import org.springframework.test.context.CacheAwareContextLoaderDelegate;
@ -82,9 +84,9 @@ final class AotMergedContextConfiguration extends MergedContextConfiguration {
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("testClass", getTestClass().getName()) .append("testClass", getTestClass())
.append("contextInitializerClass", this.contextInitializerClass.getName()) .append("contextInitializerClass", this.contextInitializerClass)
.append("original", this.original) .append("original", this.original)
.toString(); .toString();
} }

View File

@ -23,7 +23,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.log.LogMessage;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode; import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.ApplicationContextFailureProcessor; import org.springframework.test.context.ApplicationContextFailureProcessor;
@ -108,8 +107,8 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
else { else {
context = loadContextInternal(mergedContextConfiguration); context = loadContextInternal(mergedContextConfiguration);
} }
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Storing ApplicationContext [%s] in cache under key %s".formatted( logger.trace("Storing ApplicationContext [%s] in cache under key %s".formatted(
System.identityHashCode(context), mergedContextConfiguration)); System.identityHashCode(context), mergedContextConfiguration));
} }
this.contextCache.put(mergedContextConfiguration, context); this.contextCache.put(mergedContextConfiguration, context);
@ -135,8 +134,8 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
} }
} }
else { else {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Retrieved ApplicationContext [%s] from cache with key %s".formatted( logger.trace("Retrieved ApplicationContext [%s] from cache with key %s".formatted(
System.identityHashCode(context), mergedContextConfiguration)); System.identityHashCode(context), mergedContextConfiguration));
} }
} }
@ -198,7 +197,15 @@ public class DefaultCacheAwareContextLoaderDelegate implements CacheAwareContext
() -> "Failed to load AOT ApplicationContextInitializer for test class [%s]" () -> "Failed to load AOT ApplicationContextInitializer for test class [%s]"
.formatted(testClass.getName())); .formatted(testClass.getName()));
ContextLoader contextLoader = getContextLoader(aotMergedConfig); ContextLoader contextLoader = getContextLoader(aotMergedConfig);
logger.info(LogMessage.format("Loading ApplicationContext in AOT mode for %s", aotMergedConfig.getOriginal()));
if (logger.isTraceEnabled()) {
logger.trace("Loading ApplicationContext for AOT runtime for " + aotMergedConfig.getOriginal());
}
else if (logger.isDebugEnabled()) {
logger.debug("Loading ApplicationContext for AOT runtime for test class " +
aotMergedConfig.getTestClass().getName());
}
if (!((contextLoader instanceof AotContextLoader aotContextLoader) && if (!((contextLoader instanceof AotContextLoader aotContextLoader) &&
(aotContextLoader.loadContextForAotRuntime(aotMergedConfig.getOriginal(), contextInitializer) (aotContextLoader.loadContextForAotRuntime(aotMergedConfig.getOriginal(), contextInitializer)
instanceof GenericApplicationContext gac))) { instanceof GenericApplicationContext gac))) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 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.
@ -21,6 +21,8 @@ import java.util.Arrays;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.jdbc.datasource.init.ScriptUtils; import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -210,7 +212,7 @@ class MergedSqlConfig {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("dataSource", this.dataSource) .append("dataSource", this.dataSource)
.append("transactionManager", this.transactionManager) .append("transactionManager", this.transactionManager)
.append("transactionMode", this.transactionMode) .append("transactionMode", this.transactionMode)

View File

@ -247,9 +247,13 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
} }
MergedSqlConfig mergedSqlConfig = new MergedSqlConfig(sql.config(), testContext.getTestClass()); MergedSqlConfig mergedSqlConfig = new MergedSqlConfig(sql.config(), testContext.getTestClass());
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format("Processing %s for execution phase [%s] and test context %s.", logger.trace("Processing %s for execution phase [%s] and test context %s"
mergedSqlConfig, executionPhase, testContext)); .formatted(mergedSqlConfig, executionPhase, testContext));
}
else if (logger.isDebugEnabled()) {
logger.debug("Processing merged @SqlConfig attributes for execution phase [%s] and test class [%s]"
.formatted(executionPhase, testContext.getTestClass().getName()));
} }
String[] scripts = getScripts(sql, testContext.getTestClass(), testContext.getTestMethod(), classLevel); String[] scripts = getScripts(sql, testContext.getTestClass(), testContext.getTestMethod(), classLevel);
@ -265,7 +269,7 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
ResourceDatabasePopulator populator = createDatabasePopulator(mergedSqlConfig); ResourceDatabasePopulator populator = createDatabasePopulator(mergedSqlConfig);
populator.setScripts(scriptResources.toArray(new Resource[0])); populator.setScripts(scriptResources.toArray(new Resource[0]));
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Executing SQL scripts: " + ObjectUtils.nullSafeToString(scriptResources)); logger.debug("Executing SQL scripts: " + scriptResources);
} }
String dsName = mergedSqlConfig.getDataSource(); String dsName = mergedSqlConfig.getDataSource();
@ -372,9 +376,9 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
ClassPathResource classPathResource = new ClassPathResource(resourcePath); ClassPathResource classPathResource = new ClassPathResource(resourcePath);
if (classPathResource.exists()) { if (classPathResource.exists()) {
if (logger.isInfoEnabled()) { if (logger.isDebugEnabled()) {
logger.info(String.format("Detected default SQL script \"%s\" for test %s [%s]", logger.debug("Detected default SQL script \"%s\" for test %s [%s]"
prefixedResourcePath, elementType, elementName)); .formatted(prefixedResourcePath, elementType, elementName));
} }
return prefixedResourcePath; return prefixedResourcePath;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 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.
@ -135,8 +135,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
*/ */
public SpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError { public SpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError {
super(clazz); super(clazz);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "]"); logger.trace("SpringJUnit4ClassRunner constructor called with [%s]"
.formatted((clazz != null ? clazz.getName() : null)));
} }
ensureSpringRulesAreNotPresent(clazz); ensureSpringRulesAreNotPresent(clazz);
this.testContextManager = createTestContextManager(clazz); this.testContextManager = createTestContextManager(clazz);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2022 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.
@ -77,8 +77,8 @@ public class SpringRepeat extends Statement {
@Override @Override
public void evaluate() throws Throwable { public void evaluate() throws Throwable {
for (int i = 0; i < this.repeat; i++) { for (int i = 0; i < this.repeat; i++) {
if (this.repeat > 1 && logger.isInfoEnabled()) { if (this.repeat > 1 && logger.isTraceEnabled()) {
logger.info(String.format("Repetition %d of test %s#%s()", (i + 1), logger.trace(String.format("Repetition %d of test %s#%s()", (i + 1),
this.testMethod.getDeclaringClass().getSimpleName(), this.testMethod.getName())); this.testMethod.getDeclaringClass().getSimpleName(), this.testMethod.getName()));
} }
this.next.evaluate(); this.next.evaluate();

View File

@ -255,20 +255,20 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
ClassPathResource classPathResource = new ClassPathResource(resourcePath); ClassPathResource classPathResource = new ClassPathResource(resourcePath);
if (classPathResource.exists()) { if (classPathResource.exists()) {
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH + resourcePath; String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH + resourcePath;
if (logger.isInfoEnabled()) { if (logger.isDebugEnabled()) {
logger.info(String.format("Detected default resource location \"%s\" for test class [%s]", logger.debug(String.format("Detected default resource location \"%s\" for test class [%s]",
prefixedResourcePath, clazz.getName())); prefixedResourcePath, clazz.getName()));
} }
return new String[] {prefixedResourcePath}; return new String[] {prefixedResourcePath};
} }
else if (logger.isDebugEnabled()) { else if (logger.isTraceEnabled()) {
logger.debug(String.format("Did not detect default resource location for test class [%s]: " + logger.trace(String.format("Did not detect default resource location for test class [%s]: " +
"%s does not exist", clazz.getName(), classPathResource)); "%s does not exist", clazz.getName(), classPathResource));
} }
} }
if (logger.isInfoEnabled()) { if (logger.isDebugEnabled()) {
logger.info(String.format("Could not detect default resource locations for test class [%s]: " + logger.debug(String.format("Could not detect default resource locations for test class [%s]: " +
"no resource found for suffixes %s.", clazz.getName(), ObjectUtils.nullSafeToString(suffixes))); "no resource found for suffixes %s.", clazz.getName(), ObjectUtils.nullSafeToString(suffixes)));
} }

View File

@ -148,28 +148,28 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations(); boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
if (xmlLoaderDetectedDefaults) { if (xmlLoaderDetectedDefaults) {
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info(String.format("%s detected default locations for context configuration %s.", logger.trace(String.format("%s detected default locations for context configuration %s",
name(getXmlLoader()), configAttributes)); name(getXmlLoader()), configAttributes));
} }
} }
Assert.state(!configAttributes.hasClasses(), () -> String.format( Assert.state(!configAttributes.hasClasses(), () -> String.format(
"%s should NOT have detected default configuration classes for context configuration %s.", "%s should NOT have detected default configuration classes for context configuration %s",
name(getXmlLoader()), configAttributes)); name(getXmlLoader()), configAttributes));
// Now let the annotation config loader process the configuration. // Now let the annotation config loader process the configuration.
delegateProcessing(getAnnotationConfigLoader(), configAttributes); delegateProcessing(getAnnotationConfigLoader(), configAttributes);
if (configAttributes.hasClasses()) { if (configAttributes.hasClasses()) {
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info(String.format("%s detected default configuration classes for context configuration %s.", logger.trace(String.format("%s detected default configuration classes for context configuration %s",
name(getAnnotationConfigLoader()), configAttributes)); name(getAnnotationConfigLoader()), configAttributes));
} }
} }
Assert.state(xmlLoaderDetectedDefaults || !configAttributes.hasLocations(), () -> String.format( Assert.state(xmlLoaderDetectedDefaults || !configAttributes.hasLocations(), () -> String.format(
"%s should NOT have detected default locations for context configuration %s.", "%s should NOT have detected default locations for context configuration %s",
name(getAnnotationConfigLoader()), configAttributes)); name(getAnnotationConfigLoader()), configAttributes));
if (configAttributes.hasLocations() && configAttributes.hasClasses()) { if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
@ -206,8 +206,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
@Override @Override
public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception { public final ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
SmartContextLoader loader = getContextLoader(mergedConfig); SmartContextLoader loader = getContextLoader(mergedConfig);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Delegating to %s to load context for %s".formatted(name(loader), mergedConfig)); logger.trace("Delegating to %s to load context for %s".formatted(name(loader), mergedConfig));
} }
return loader.loadContext(mergedConfig); return loader.loadContext(mergedConfig);
} }
@ -229,8 +229,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
@Override @Override
public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception { public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception {
AotContextLoader loader = getAotContextLoader(mergedConfig); AotContextLoader loader = getAotContextLoader(mergedConfig);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Delegating to %s to load context for AOT processing for %s" logger.trace("Delegating to %s to load context for AOT processing for %s"
.formatted(name(loader), mergedConfig)); .formatted(name(loader), mergedConfig));
} }
return loader.loadContextForAotProcessing(mergedConfig); return loader.loadContextForAotProcessing(mergedConfig);
@ -256,8 +256,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
ApplicationContextInitializer<ConfigurableApplicationContext> initializer) throws Exception { ApplicationContextInitializer<ConfigurableApplicationContext> initializer) throws Exception {
AotContextLoader loader = getAotContextLoader(mergedConfig); AotContextLoader loader = getAotContextLoader(mergedConfig);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Delegating to %s to load context for AOT execution for %s" logger.trace("Delegating to %s to load context for AOT execution for %s"
.formatted(name(loader), mergedConfig)); .formatted(name(loader), mergedConfig));
} }
return loader.loadContextForAotRuntime(mergedConfig, initializer); return loader.loadContextForAotRuntime(mergedConfig, initializer);
@ -310,8 +310,9 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) { private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Delegating to %s to process context configuration %s.".formatted(name(loader), configAttributes)); logger.trace("Delegating to %s to process context configuration %s"
.formatted(name(loader), configAttributes));
} }
loader.processContextConfiguration(configAttributes); loader.processContextConfiguration(configAttributes);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -103,11 +103,19 @@ public abstract class AbstractDirtiesContextTestExecutionListener extends Abstra
MethodMode methodMode = (methodAnnotated ? methodAnn.methodMode() : null); MethodMode methodMode = (methodAnnotated ? methodAnn.methodMode() : null);
ClassMode classMode = (classAnnotated ? classAnn.classMode() : null); ClassMode classMode = (classAnnotated ? classAnn.classMode() : null);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
String phase = (requiredClassMode.name().startsWith("BEFORE") ? "Before" : "After"); logger.trace("""
logger.debug(String.format("%s test method: context %s, class annotated with @DirtiesContext [%s] " %s test method: context %s, class annotated with @DirtiesContext [%s] \
+ "with mode [%s], method annotated with @DirtiesContext [%s] with mode [%s].", phase, testContext, with mode [%s], method annotated with @DirtiesContext [%s] with mode [%s]"""
classAnnotated, classMode, methodAnnotated, methodMode)); .formatted(getPhase(requiredMethodMode), testContext, classAnnotated, classMode,
methodAnnotated, methodMode));
}
else if (logger.isDebugEnabled()) {
logger.debug("""
%s test method: class [%s], method [%s], class annotated with @DirtiesContext [%s] \
with mode [%s], method annotated with @DirtiesContext [%s] with mode [%s]"""
.formatted(getPhase(requiredMethodMode), testClass.getSimpleName(),
testMethod.getName(), classAnnotated, classMode, methodAnnotated, methodMode));
} }
if ((methodMode == requiredMethodMode) || (classMode == requiredClassMode)) { if ((methodMode == requiredMethodMode) || (classMode == requiredClassMode)) {
@ -138,11 +146,13 @@ public abstract class AbstractDirtiesContextTestExecutionListener extends Abstra
boolean classAnnotated = (dirtiesContext != null); boolean classAnnotated = (dirtiesContext != null);
ClassMode classMode = (classAnnotated ? dirtiesContext.classMode() : null); ClassMode classMode = (classAnnotated ? dirtiesContext.classMode() : null);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
String phase = (requiredClassMode.name().startsWith("BEFORE") ? "Before" : "After"); logger.trace("%s test class: context %s, class annotated with @DirtiesContext [%s] with mode [%s]"
logger.debug(String.format( .formatted(getPhase(requiredClassMode), testContext, classAnnotated, classMode));
"%s test class: context %s, class annotated with @DirtiesContext [%s] with mode [%s].", phase, }
testContext, classAnnotated, classMode)); else if (logger.isDebugEnabled()) {
logger.debug("%s test class: class [%s], class annotated with @DirtiesContext [%s] with mode [%s]"
.formatted(getPhase(requiredClassMode), testClass.getSimpleName(), classAnnotated, classMode));
} }
if (classMode == requiredClassMode) { if (classMode == requiredClassMode) {
@ -150,4 +160,12 @@ public abstract class AbstractDirtiesContextTestExecutionListener extends Abstra
} }
} }
private static String getPhase(ClassMode classMode) {
return (classMode.name().startsWith("BEFORE") ? "Before" : "After");
}
private static String getPhase(MethodMode methodMode) {
return (methodMode.name().startsWith("BEFORE") ? "Before" : "After");
}
} }

View File

@ -153,8 +153,12 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null"); Assert.notNull(mergedConfig, "MergedContextConfiguration must not be null");
Assert.notNull(initializer, "ApplicationContextInitializer must not be null"); Assert.notNull(initializer, "ApplicationContextInitializer must not be null");
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Loading ApplicationContext for AOT runtime for merged context configuration " + mergedConfig); logger.trace("Loading ApplicationContext for AOT runtime for " + mergedConfig);
}
else if (logger.isDebugEnabled()) {
logger.debug("Loading ApplicationContext for AOT runtime for test class " +
mergedConfig.getTestClass().getName());
} }
validateMergedContextConfiguration(mergedConfig); validateMergedContextConfiguration(mergedConfig);
@ -187,9 +191,13 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
private final GenericApplicationContext loadContext( private final GenericApplicationContext loadContext(
MergedContextConfiguration mergedConfig, boolean forAotProcessing) throws Exception { MergedContextConfiguration mergedConfig, boolean forAotProcessing) throws Exception {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Loading ApplicationContext %sfor merged context configuration %s" logger.trace("Loading ApplicationContext %sfor %s".formatted(
.formatted((forAotProcessing ? "for AOT processing " : ""), mergedConfig)); (forAotProcessing ? "for AOT processing " : ""), mergedConfig));
}
else if (logger.isDebugEnabled()) {
logger.debug("Loading ApplicationContext %sfor test class %s".formatted(
(forAotProcessing ? "for AOT processing " : ""), mergedConfig.getTestClass().getName()));
} }
validateMergedContextConfiguration(mergedConfig); validateMergedContextConfiguration(mergedConfig);

View File

@ -123,8 +123,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
// Use defaults? // Use defaults?
if (descriptor == null) { if (descriptor == null) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format("@TestExecutionListeners is not present for class [%s]: using defaults.", logger.trace(String.format("@TestExecutionListeners is not present for class [%s]: using defaults.",
clazz.getName())); clazz.getName()));
} }
usingDefaults = true; usingDefaults = true;
@ -147,8 +147,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
// locally declared listeners with the defaults. // locally declared listeners with the defaults.
if ((!inheritListeners || parentDescriptor == null) && if ((!inheritListeners || parentDescriptor == null) &&
testExecutionListeners.mergeMode() == MergeMode.MERGE_WITH_DEFAULTS) { testExecutionListeners.mergeMode() == MergeMode.MERGE_WITH_DEFAULTS) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format("Merging default listeners with listeners configured via " + logger.trace(String.format("Merging default listeners with listeners configured via " +
"@TestExecutionListeners for class [%s].", descriptor.getRootDeclaringClass().getName())); "@TestExecutionListeners for class [%s].", descriptor.getRootDeclaringClass().getName()));
} }
usingDefaults = true; usingDefaults = true;
@ -176,8 +176,13 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
AnnotationAwareOrderComparator.sort(listeners); AnnotationAwareOrderComparator.sort(listeners);
} }
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info("Using TestExecutionListeners: " + listeners); logger.trace("Using TestExecutionListeners for test class [%s]: %s"
.formatted(clazz.getName(), listeners));
}
else if (logger.isDebugEnabled()) {
logger.debug("Using TestExecutionListeners for test class [%s]: %s"
.formatted(clazz.getSimpleName(), classSimpleNames(listeners)));
} }
return listeners; return listeners;
} }
@ -204,8 +209,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
SpringFactoriesLoader loader = SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader()); SpringFactoriesLoader loader = SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader());
List<TestExecutionListener> listeners = List<TestExecutionListener> listeners =
loader.load(TestExecutionListener.class, this::handleInstantiationFailure); loader.load(TestExecutionListener.class, this::handleInstantiationFailure);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Loaded default TestExecutionListener implementations from location [%s]: %s" logger.trace("Loaded default TestExecutionListener implementations from location [%s]: %s"
.formatted(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION, classNames(listeners))); .formatted(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION, classNames(listeners)));
} }
return Collections.unmodifiableList(listeners); return Collections.unmodifiableList(listeners);
@ -284,10 +289,15 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
Collections.singletonList(new ContextConfigurationAttributes(testClass)); Collections.singletonList(new ContextConfigurationAttributes(testClass));
ContextLoader contextLoader = resolveContextLoader(testClass, defaultConfigAttributesList); ContextLoader contextLoader = resolveContextLoader(testClass, defaultConfigAttributesList);
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info(String.format( logger.trace(String.format(
"Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s], using %s", "Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]: using %s",
testClass.getName(), contextLoader.getClass().getSimpleName())); testClass.getName(), contextLoader.getClass().getName()));
}
else if (logger.isDebugEnabled()) {
logger.debug(String.format(
"Neither @ContextConfiguration nor @ContextHierarchy found for test class [%s]: using %s",
testClass.getSimpleName(), contextLoader.getClass().getSimpleName()));
} }
return buildMergedContextConfiguration(testClass, defaultConfigAttributesList, null, return buildMergedContextConfiguration(testClass, defaultConfigAttributesList, null,
cacheAwareContextLoaderDelegate, false); cacheAwareContextLoaderDelegate, false);
@ -387,8 +397,13 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
customizers.add(customizer); customizers.add(customizer);
} }
} }
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info("Using ContextCustomizers: " + customizers); logger.trace("Using ContextCustomizers for test class [%s]: %s"
.formatted(testClass.getName(), customizers));
}
else if (logger.isDebugEnabled()) {
logger.debug("Using ContextCustomizers for test class [%s]: %s"
.formatted(testClass.getSimpleName(), classSimpleNames(customizers)));
} }
return customizers; return customizers;
} }
@ -405,8 +420,8 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
SpringFactoriesLoader loader = SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader()); SpringFactoriesLoader loader = SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader());
List<ContextCustomizerFactory> factories = List<ContextCustomizerFactory> factories =
loader.load(ContextCustomizerFactory.class, this::handleInstantiationFailure); loader.load(ContextCustomizerFactory.class, this::handleInstantiationFailure);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Loaded ContextCustomizerFactory implementations from location [%s]: %s" logger.trace("Loaded ContextCustomizerFactory implementations from location [%s]: %s"
.formatted(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION, classNames(factories))); .formatted(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION, classNames(factories)));
} }
return factories; return factories;
@ -476,15 +491,17 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
for (ContextConfigurationAttributes configAttributes : configAttributesList) { for (ContextConfigurationAttributes configAttributes : configAttributesList) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Resolving ContextLoader for context configuration attributes %s", logger.trace("Resolving ContextLoader for context configuration attributes " + configAttributes);
configAttributes));
} }
Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass(); Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass();
if (ContextLoader.class != contextLoaderClass) { if (ContextLoader.class != contextLoaderClass) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace("Found explicit ContextLoader class [%s] for context configuration attributes %s"
"Found explicit ContextLoader class [%s] for context configuration attributes %s", .formatted(contextLoaderClass.getName(), configAttributes));
contextLoaderClass.getName(), configAttributes)); }
else if (logger.isDebugEnabled()) {
logger.debug("Found explicit ContextLoader class [%s] for test class [%s]"
.formatted(contextLoaderClass.getSimpleName(), configAttributes.getDeclaringClass().getSimpleName()));
} }
return contextLoaderClass; return contextLoaderClass;
} }
@ -597,7 +614,11 @@ public abstract class AbstractTestContextBootstrapper implements TestContextBoot
} }
private static List<String> classNames(List<?> components) { private static List<String> classSimpleNames(Collection<?> components) {
return components.stream().map(Object::getClass).map(Class::getSimpleName).toList();
}
private static List<String> classNames(Collection<?> components) {
return components.stream().map(Object::getClass).map(Class::getName).toList(); return components.stream().map(Object::getClass).map(Class::getName).toList();
} }

View File

@ -76,10 +76,9 @@ abstract class ActiveProfilesUtils {
AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, ActiveProfiles.class); AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, ActiveProfiles.class);
List<String[]> profileArrays = new ArrayList<>(); List<String[]> profileArrays = new ArrayList<>();
if (descriptor == null && logger.isDebugEnabled()) { if (descriptor == null && logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace("Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]"
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", .formatted(ActiveProfiles.class.getName(), testClass.getName()));
ActiveProfiles.class.getName(), testClass.getName()));
} }
while (descriptor != null) { while (descriptor != null) {
@ -87,8 +86,8 @@ abstract class ActiveProfilesUtils {
ActiveProfiles annotation = descriptor.getAnnotation(); ActiveProfiles annotation = descriptor.getAnnotation();
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ActiveProfiles [%s] for declaring class [%s]", logger.trace("Retrieved @ActiveProfiles [%s] for declaring class [%s]"
annotation, descriptor.getDeclaringClass().getName())); .formatted(annotation, descriptor.getDeclaringClass().getName()));
} }
ActiveProfilesResolver resolver; ActiveProfilesResolver resolver;
@ -101,8 +100,8 @@ abstract class ActiveProfilesUtils {
resolver = BeanUtils.instantiateClass(resolverClass, ActiveProfilesResolver.class); resolver = BeanUtils.instantiateClass(resolverClass, ActiveProfilesResolver.class);
} }
catch (Exception ex) { catch (Exception ex) {
String msg = String.format("Could not instantiate ActiveProfilesResolver of type [%s] " + String msg = "Could not instantiate ActiveProfilesResolver of type [%s] for test class [%s]"
"for test class [%s]", resolverClass.getName(), rootDeclaringClass.getName()); .formatted(resolverClass.getName(), rootDeclaringClass.getName());
logger.error(msg); logger.error(msg);
throw new IllegalStateException(msg, ex); throw new IllegalStateException(msg, ex);
} }

View File

@ -17,6 +17,7 @@
package org.springframework.test.context.support; package org.springframework.test.context.support;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -183,11 +184,15 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) { protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) {
Class<?>[] componentClasses = mergedConfig.getClasses(); Class<?>[] componentClasses = mergedConfig.getClasses();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: " + Arrays.toString(componentClasses)); logger.debug("Registering component classes: " + classNames(componentClasses));
} }
new AnnotatedBeanDefinitionReader(context).register(componentClasses); new AnnotatedBeanDefinitionReader(context).register(componentClasses);
} }
private static List<String> classNames(Class<?>... classes) {
return Arrays.stream(classes).map(Class::getName).toList();
}
/** /**
* {@code AnnotationConfigContextLoader} should be used as a * {@code AnnotationConfigContextLoader} should be used as a
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}, * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -59,8 +59,8 @@ public class DefaultActiveProfilesResolver implements ActiveProfilesResolver {
AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, ActiveProfiles.class); AnnotationDescriptor<ActiveProfiles> descriptor = findAnnotationDescriptor(testClass, ActiveProfiles.class);
if (descriptor == null) { if (descriptor == null) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace(String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", "Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]",
ActiveProfiles.class.getName(), testClass.getName())); ActiveProfiles.class.getName(), testClass.getName()));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 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.
@ -16,6 +16,8 @@
package org.springframework.test.context.support; package org.springframework.test.context.support;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.test.context.BootstrapContext; import org.springframework.test.context.BootstrapContext;
import org.springframework.test.context.CacheAwareContextLoaderDelegate; import org.springframework.test.context.CacheAwareContextLoaderDelegate;
@ -67,9 +69,9 @@ public class DefaultBootstrapContext implements BootstrapContext {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this)// return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("testClass", this.testClass.getName())// .append("testClass", this.testClass)
.append("cacheAwareContextLoaderDelegate", this.cacheAwareContextLoaderDelegate.getClass().getName())// .append("cacheAwareContextLoaderDelegate", this.cacheAwareContextLoaderDelegate.getClass())
.toString(); .toString();
} }

View File

@ -23,6 +23,8 @@ import java.util.function.Function;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode; import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
@ -238,7 +240,7 @@ public class DefaultTestContext implements TestContext {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("testClass", this.testClass) .append("testClass", this.testClass)
.append("testInstance", this.testInstance) .append("testInstance", this.testInstance)
.append("testMethod", this.testMethod) .append("testMethod", this.testMethod)

View File

@ -84,8 +84,11 @@ public class DependencyInjectionTestExecutionListener extends AbstractTestExecut
*/ */
@Override @Override
public void prepareTestInstance(TestContext testContext) throws Exception { public void prepareTestInstance(TestContext testContext) throws Exception {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Performing dependency injection for test context " + testContext); logger.trace("Performing dependency injection for test context " + testContext);
}
else if (logger.isDebugEnabled()) {
logger.debug("Performing dependency injection for test class " + testContext.getTestClass().getName());
} }
if (runningInAotMode(testContext.getTestClass())) { if (runningInAotMode(testContext.getTestClass())) {
injectDependenciesInAotMode(testContext); injectDependenciesInAotMode(testContext);
@ -105,8 +108,11 @@ public class DependencyInjectionTestExecutionListener extends AbstractTestExecut
@Override @Override
public void beforeTestMethod(TestContext testContext) throws Exception { public void beforeTestMethod(TestContext testContext) throws Exception {
if (Boolean.TRUE.equals(testContext.getAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE))) { if (Boolean.TRUE.equals(testContext.getAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE))) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Reinjecting dependencies for test context [" + testContext + "]."); logger.trace("Reinjecting dependencies for test context " + testContext);
}
else if (logger.isDebugEnabled()) {
logger.debug("Reinjecting dependencies for test class " + testContext.getTestClass().getName());
} }
if (runningInAotMode(testContext.getTestClass())) { if (runningInAotMode(testContext.getTestClass())) {
injectDependenciesInAotMode(testContext); injectDependenciesInAotMode(testContext);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -18,6 +18,8 @@ package org.springframework.test.context.support;
import java.util.Arrays; import java.util.Arrays;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
@ -125,9 +127,9 @@ class MergedTestPropertySources {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("locations", Arrays.toString(this.locations)) .append("locations", this.locations)
.append("properties", Arrays.toString(this.properties)) .append("properties", this.properties)
.toString(); .toString();
} }

View File

@ -26,6 +26,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.log.LogMessage; import org.springframework.core.log.LogMessage;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
@ -159,8 +161,8 @@ class TestPropertySourceAttributes {
throw new IllegalStateException(msg); throw new IllegalStateException(msg);
} }
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH + resourcePath; String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH + resourcePath;
if (logger.isInfoEnabled()) { if (logger.isDebugEnabled()) {
logger.info(String.format("Detected default properties file \"%s\" for test class [%s]", logger.debug(String.format("Detected default properties file \"%s\" for test class [%s]",
prefixedResourcePath, testClass.getName())); prefixedResourcePath, testClass.getName()));
} }
return prefixedResourcePath; return prefixedResourcePath;
@ -262,8 +264,8 @@ class TestPropertySourceAttributes {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("declaringClass", this.declaringClass.getName()) .append("declaringClass", this.declaringClass)
.append("locations", this.locations) .append("locations", this.locations)
.append("inheritLocations", this.inheritLocations) .append("inheritLocations", this.inheritLocations)
.append("properties", this.properties) .append("properties", this.properties)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -130,8 +130,8 @@ public abstract class TestPropertySourceUtils {
boolean duplicationDetected = boolean duplicationDetected =
(currentAttributes.equals(previousAttributes) && !currentAttributes.isEmpty()); (currentAttributes.equals(previousAttributes) && !currentAttributes.isEmpty());
if (duplicationDetected && logger.isDebugEnabled()) { if (duplicationDetected && logger.isTraceEnabled()) {
logger.debug(String.format("Ignoring duplicate %s declaration on %s since it is also declared on %s", logger.trace(String.format("Ignoring duplicate %s declaration on %s since it is also declared on %s",
currentAttributes, currentAttributes.getDeclaringClass().getName(), currentAttributes, currentAttributes.getDeclaringClass().getName(),
previousAttributes.getDeclaringClass().getName())); previousAttributes.getDeclaringClass().getName()));
} }
@ -143,7 +143,7 @@ public abstract class TestPropertySourceUtils {
List<String> locations = new ArrayList<>(); List<String> locations = new ArrayList<>();
for (TestPropertySourceAttributes attrs : attributesList) { for (TestPropertySourceAttributes attrs : attributesList) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Processing locations for TestPropertySource attributes %s", attrs)); logger.trace("Processing locations for " + attrs);
} }
String[] locationsArray = TestContextResourceUtils.convertToClasspathResourcePaths( String[] locationsArray = TestContextResourceUtils.convertToClasspathResourcePaths(
attrs.getDeclaringClass(), true, attrs.getLocations()); attrs.getDeclaringClass(), true, attrs.getLocations());
@ -159,7 +159,7 @@ public abstract class TestPropertySourceUtils {
List<String> properties = new ArrayList<>(); List<String> properties = new ArrayList<>();
for (TestPropertySourceAttributes attrs : attributesList) { for (TestPropertySourceAttributes attrs : attributesList) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Processing inlined properties for TestPropertySource attributes %s", attrs)); logger.trace("Processing inlined properties for " + attrs);
} }
String[] attrProps = attrs.getProperties(); String[] attrProps = attrs.getProperties();
properties.addAll(0, Arrays.asList(attrProps)); properties.addAll(0, Arrays.asList(attrProps));
@ -268,8 +268,8 @@ public abstract class TestPropertySourceUtils {
Assert.notNull(environment, "'environment' must not be null"); Assert.notNull(environment, "'environment' must not be null");
Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null"); Assert.notNull(inlinedProperties, "'inlinedProperties' must not be null");
if (!ObjectUtils.isEmpty(inlinedProperties)) { if (!ObjectUtils.isEmpty(inlinedProperties)) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Adding inlined properties to environment: " + logger.trace("Adding inlined properties to environment: " +
ObjectUtils.nullSafeToString(inlinedProperties)); ObjectUtils.nullSafeToString(inlinedProperties));
} }
MapPropertySource ps = (MapPropertySource) MapPropertySource ps = (MapPropertySource)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 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.
@ -218,9 +218,9 @@ public abstract class TestContextTransactionUtils {
} }
private static void logBeansException(TestContext testContext, BeansException ex, Class<?> beanType) { private static void logBeansException(TestContext testContext, BeansException ex, Class<?> beanType) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format("Caught exception while retrieving %s for test context %s", logger.trace("Caught exception while retrieving %s for test context %s"
beanType.getSimpleName(), testContext), ex); .formatted(beanType.getSimpleName(), testContext), ex);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -103,10 +103,14 @@ class TransactionContext {
this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition); this.transactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);
int transactionsStarted = this.transactionsStarted.incrementAndGet(); int transactionsStarted = this.transactionsStarted.incrementAndGet();
if (logger.isInfoEnabled()) { if (logger.isTraceEnabled()) {
logger.info(String.format( logger.trace("Began transaction (%d) for test context %s; transaction manager [%s]; rollback [%s]"
"Began transaction (%s) for test context %s; transaction manager [%s]; rollback [%s]", .formatted(transactionsStarted, this.testContext, this.transactionManager, this.flaggedForRollback));
transactionsStarted, this.testContext, this.transactionManager, this.flaggedForRollback)); }
else if (logger.isDebugEnabled()) {
logger.debug("Began transaction (%d) for test class [%s]; test method [%s]; transaction manager [%s]; rollback [%s]"
.formatted(transactionsStarted, this.testContext.getTestClass().getName(),
this.testContext.getTestMethod().getName(), this.transactionManager, this.flaggedForRollback));
} }
} }
@ -135,9 +139,16 @@ class TransactionContext {
this.transactionStatus = null; this.transactionStatus = null;
} }
if (logger.isInfoEnabled()) { int transactionsStarted = this.transactionsStarted.get();
logger.info((this.flaggedForRollback ? "Rolled back" : "Committed") + if (logger.isTraceEnabled()) {
" transaction for test: " + this.testContext); logger.trace("%s transaction (%d) for test context: %s"
.formatted((this.flaggedForRollback ? "Rolled back" : "Committed"),
transactionsStarted, this.testContext));
}
else if (logger.isDebugEnabled()) {
logger.debug("%s transaction (%d) for test class [%s]; test method [%s]"
.formatted((this.flaggedForRollback ? "Rolled back" : "Committed"), transactionsStarted,
this.testContext.getTestClass().getName(), this.testContext.getTestMethod().getName()));
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 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.
@ -210,9 +210,13 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(testContext, transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(testContext,
transactionAttribute); transactionAttribute);
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Explicit transaction definition [" + transactionAttribute + logger.trace("Explicit transaction definition [%s] found for test context %s"
"] found for test context " + testContext); .formatted(transactionAttribute, testContext));
}
else if (logger.isDebugEnabled()) {
logger.debug("Explicit transaction definition [%s] found for test class [%s] and test method [%s]"
.formatted(transactionAttribute, testClass.getName(), testMethod.getName()));
} }
if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || if (transactionAttribute.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED ||
@ -271,11 +275,17 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
*/ */
protected void runBeforeTransactionMethods(TestContext testContext) throws Exception { protected void runBeforeTransactionMethods(TestContext testContext) throws Exception {
try { try {
List<Method> methods = getAnnotatedMethods(testContext.getTestClass(), BeforeTransaction.class); Class<?> testClass = testContext.getTestClass();
List<Method> methods = getAnnotatedMethods(testClass, BeforeTransaction.class);
Collections.reverse(methods); Collections.reverse(methods);
for (Method method : methods) { for (Method method : methods) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Executing @BeforeTransaction method [" + method + "] for test context " + testContext); logger.trace("Executing @BeforeTransaction method [%s] for test context %s"
.formatted(method, testContext));
}
else if (logger.isDebugEnabled()) {
logger.debug("Executing @BeforeTransaction method [%s] for test class [%s]"
.formatted(method, testClass.getName()));
} }
ReflectionUtils.makeAccessible(method); ReflectionUtils.makeAccessible(method);
method.invoke(testContext.getTestInstance()); method.invoke(testContext.getTestInstance());
@ -284,7 +294,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
catch (InvocationTargetException ex) { catch (InvocationTargetException ex) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error("Exception encountered while executing @BeforeTransaction methods for test context " + logger.error("Exception encountered while executing @BeforeTransaction methods for test context " +
testContext + ".", ex.getTargetException()); testContext, ex.getTargetException());
} }
ReflectionUtils.rethrowException(ex.getTargetException()); ReflectionUtils.rethrowException(ex.getTargetException());
} }
@ -301,11 +311,17 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
protected void runAfterTransactionMethods(TestContext testContext) throws Exception { protected void runAfterTransactionMethods(TestContext testContext) throws Exception {
Throwable afterTransactionException = null; Throwable afterTransactionException = null;
List<Method> methods = getAnnotatedMethods(testContext.getTestClass(), AfterTransaction.class); Class<?> testClass = testContext.getTestClass();
List<Method> methods = getAnnotatedMethods(testClass, AfterTransaction.class);
for (Method method : methods) { for (Method method : methods) {
try { try {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Executing @AfterTransaction method [" + method + "] for test context " + testContext); logger.trace("Executing @AfterTransaction method [%s] for test context %s"
.formatted(method, testContext));
}
else if (logger.isDebugEnabled()) {
logger.debug("Executing @AfterTransaction method [%s] for test class [%s]"
.formatted(method, testClass.getName()));
} }
ReflectionUtils.makeAccessible(method); ReflectionUtils.makeAccessible(method);
method.invoke(testContext.getTestInstance()); method.invoke(testContext.getTestInstance());
@ -430,22 +446,28 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
*/ */
protected final boolean isRollback(TestContext testContext) throws Exception { protected final boolean isRollback(TestContext testContext) throws Exception {
boolean rollback = isDefaultRollback(testContext); boolean rollback = isDefaultRollback(testContext);
Rollback rollbackAnnotation = Method testMethod = testContext.getTestMethod();
AnnotatedElementUtils.findMergedAnnotation(testContext.getTestMethod(), Rollback.class); Rollback rollbackAnnotation = AnnotatedElementUtils.findMergedAnnotation(testMethod, Rollback.class);
if (rollbackAnnotation != null) { if (rollbackAnnotation != null) {
boolean rollbackOverride = rollbackAnnotation.value(); boolean rollbackOverride = rollbackAnnotation.value();
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace("Method-level @Rollback(%s) overrides default rollback [%s] for test context %s"
"Method-level @Rollback(%s) overrides default rollback [%s] for test context %s.", .formatted(rollbackOverride, rollback, testContext));
rollbackOverride, rollback, testContext)); }
else if (logger.isDebugEnabled()) {
logger.debug("Method-level @Rollback(%s) overrides default rollback [%s] for test method [%s]"
.formatted(rollbackOverride, rollback, testMethod));
} }
rollback = rollbackOverride; rollback = rollbackOverride;
} }
else { else {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace("No method-level @Rollback override: using default rollback [%s] for test context %s"
"No method-level @Rollback override: using default rollback [%s] for test context %s.", .formatted(rollback, testContext));
rollback, testContext)); }
else if (logger.isDebugEnabled()) {
logger.debug("No method-level @Rollback override: using default rollback [%s] for test method [%s]"
.formatted(rollback, testMethod));
} }
} }
return rollback; return rollback;

View File

@ -154,6 +154,14 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
.formatted(mergedConfig)); .formatted(mergedConfig));
} }
if (logger.isTraceEnabled()) {
logger.trace("Loading WebApplicationContext for AOT runtime for " + mergedConfig);
}
else if (logger.isDebugEnabled()) {
logger.debug("Loading WebApplicationContext for AOT runtime for test class " +
mergedConfig.getTestClass().getName());
}
validateMergedContextConfiguration(webMergedConfig); validateMergedContextConfiguration(webMergedConfig);
GenericWebApplicationContext context = createContext(); GenericWebApplicationContext context = createContext();
@ -192,9 +200,13 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa
.formatted(mergedConfig)); .formatted(mergedConfig));
} }
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug("Loading WebApplicationContext %sfor merged context configuration %s" logger.trace("Loading WebApplicationContext %sfor %s".formatted(
.formatted((forAotProcessing ? "for AOT processing " : ""), mergedConfig)); (forAotProcessing ? "for AOT processing " : ""), mergedConfig));
}
else if (logger.isDebugEnabled()) {
logger.debug("Loading WebApplicationContext %sfor test class %s".formatted(
(forAotProcessing ? "for AOT processing " : ""), mergedConfig.getTestClass().getName()));
} }
validateMergedContextConfiguration(webMergedConfig); validateMergedContextConfiguration(webMergedConfig);

View File

@ -161,8 +161,11 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
@Override @Override
public void afterTestMethod(TestContext testContext) throws Exception { public void afterTestMethod(TestContext testContext) throws Exception {
if (Boolean.TRUE.equals(testContext.getAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE))) { if (Boolean.TRUE.equals(testContext.getAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE))) {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext)); logger.trace("Resetting RequestContextHolder for test context " + testContext);
}
else if (logger.isDebugEnabled()) {
logger.debug("Resetting RequestContextHolder for test class " + testContext.getTestClass().getName());
} }
RequestContextHolder.resetRequestAttributes(); RequestContextHolder.resetRequestAttributes();
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE, testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,
@ -194,10 +197,13 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
"The WebApplicationContext for test context %s must be configured with a MockServletContext.", "The WebApplicationContext for test context %s must be configured with a MockServletContext.",
testContext)); testContext));
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debug(String.format( logger.trace("Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, " +
"Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.", "and RequestContextHolder for test context " + testContext);
testContext)); }
else if (logger.isDebugEnabled()) {
logger.debug("Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, " +
"and RequestContextHolder for test class " + testContext.getTestClass().getName());
} }
MockServletContext mockServletContext = (MockServletContext) servletContext; MockServletContext mockServletContext = (MockServletContext) servletContext;

View File

@ -19,13 +19,14 @@ package org.springframework.test.context.web;
import java.util.Set; import java.util.Set;
import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.style.DefaultToStringStyler;
import org.springframework.core.style.SimpleValueStyler;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.context.CacheAwareContextLoaderDelegate; import org.springframework.test.context.CacheAwareContextLoaderDelegate;
import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextLoader; import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -197,17 +198,17 @@ public class WebMergedContextConfiguration extends MergedContextConfiguration {
*/ */
@Override @Override
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this, new DefaultToStringStyler(new SimpleValueStyler()))
.append("testClass", getTestClass()) .append("testClass", getTestClass())
.append("locations", ObjectUtils.nullSafeToString(getLocations())) .append("locations", getLocations())
.append("classes", ObjectUtils.nullSafeToString(getClasses())) .append("classes", getClasses())
.append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses())) .append("contextInitializerClasses", getContextInitializerClasses())
.append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles())) .append("activeProfiles", getActiveProfiles())
.append("propertySourceLocations", ObjectUtils.nullSafeToString(getPropertySourceLocations())) .append("propertySourceLocations", getPropertySourceLocations())
.append("propertySourceProperties", ObjectUtils.nullSafeToString(getPropertySourceProperties())) .append("propertySourceProperties", getPropertySourceProperties())
.append("contextCustomizers", getContextCustomizers()) .append("contextCustomizers", getContextCustomizers())
.append("resourceBasePath", getResourceBasePath()) .append("resourceBasePath", getResourceBasePath())
.append("contextLoader", nullSafeClassName(getContextLoader())) .append("contextLoader", (getContextLoader() != null ? getContextLoader().getClass() : null))
.append("parent", getParent()) .append("parent", getParent())
.toString(); .toString();
} }

View File

@ -14,7 +14,7 @@
<Logger name="org.springframework.test.context.TestContext" level="warn" /> <Logger name="org.springframework.test.context.TestContext" level="warn" />
<Logger name="org.springframework.test.context.TestContextManager" level="warn" /> <Logger name="org.springframework.test.context.TestContextManager" level="warn" />
<Logger name="org.springframework.test.context.ContextLoaderUtils" level="warn" /> <Logger name="org.springframework.test.context.ContextLoaderUtils" level="warn" />
<Logger name="org.springframework.test.context.aot" level="debug" /> <Logger name="org.springframework.test.context.aot" level="info" />
<Logger name="org.springframework.test.context.cache" level="warn" /> <Logger name="org.springframework.test.context.cache" level="warn" />
<Logger name="org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate" level="info" /> <Logger name="org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate" level="info" />
<Logger name="org.springframework.test.context.junit4.rules" level="warn" /> <Logger name="org.springframework.test.context.junit4.rules" level="warn" />