Utilities for managing test-specific properties, environment variables, and system properties during test execution.
org.springframework.boot.test.util
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.util.TestPropertyValues.Type;
import org.springframework.boot.test.util.ApplicationContextTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;Full Package: org.springframework.boot.test.util.TestPropertyValues
Fluent API for creating and applying test property values.
public final class TestPropertyValues {
// Factory methods - all accept varargs, can be empty
public static TestPropertyValues of(String... pairs); // "key=value"
public static TestPropertyValues of(Map<String, String> map);
public static TestPropertyValues of(Iterable<String> pairs);
public static TestPropertyValues of(Stream<String> stream);
public static <T> TestPropertyValues of(Stream<T> stream, Function<T, Pair> mapper); // @since 2.4.0
public static TestPropertyValues empty();
// Builder methods - chainable
public TestPropertyValues and(String... pairs);
public TestPropertyValues and(Iterable<String> pairs); // @since 2.4.0
public TestPropertyValues and(Stream<String> stream); // @since 2.4.0
public TestPropertyValues and(Map<String, String> map); // @since 2.4.0
public <T> TestPropertyValues and(Stream<T> stream, Function<T, Pair> mapper); // @since 2.4.0
// Application methods - cannot be null
public void applyTo(ConfigurableApplicationContext context);
public void applyTo(ConfigurableEnvironment environment);
public void applyTo(ConfigurableEnvironment environment, Type type);
public void applyTo(ConfigurableEnvironment environment, Type type, String name);
// System properties - temporary, auto-removed after action
public void applyToSystemProperties(Runnable action); // @since 3.0.0
public <T> T applyToSystemProperties(Callable<T> call);
enum Type {
SYSTEM_ENVIRONMENT, // System environment style
MAP; // Map style (default)
/**
* Get the property source class for this type
* @return the property source class
*/
public Class<? extends MapPropertySource> getSourceClass();
}
/**
* Pair of property name and value
* @since 2.4.0
*/
public static final class Pair {
/**
* Add this pair to a map
* @param properties the properties map to add to
*/
public void addTo(Map<String, @Nullable Object> properties);
/**
* Parse a string into a Pair
* @param pair the "key=value" string
* @return the Pair
*/
public static Pair parse(String pair);
/**
* Create a Pair from a map entry
* @param entry the map entry
* @return the Pair
* @since 2.4.0
*/
public static Pair fromMapEntry(Map.Entry<String, String> entry);
/**
* Create a Pair from key and value
* @param name the property name
* @param value the property value
* @return the Pair
* @since 2.4.0
*/
public static Pair of(String name, String value);
}
}import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.util.TestPropertyValues;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class PropertyTest {
@Test
void testWithProperties() {
new ApplicationContextRunner()
.run(context -> {
TestPropertyValues
.of("app.name=test", "app.timeout=30")
.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.name"))
.isEqualTo("test");
});
}
}@Test
void testSystemProperties() {
TestPropertyValues
.of("java.io.tmpdir=/tmp/test")
.applyToSystemProperties(() -> {
// Property available here
String tmpDir = System.getProperty("java.io.tmpdir");
assertThat(tmpDir).isEqualTo("/tmp/test");
});
// Property removed here
}TestPropertyValues props = TestPropertyValues
.of("db.url=jdbc:h2:mem:test")
.and("db.username=sa")
.and(Map.of("db.password", ""));@Test
void testFromMap() {
Map<String, String> config = Map.of(
"server.port", "8080",
"server.address", "localhost",
"server.compression.enabled", "true"
);
new ApplicationContextRunner()
.run(context -> {
TestPropertyValues.of(config).applyTo(context);
assertThat(context.getEnvironment().getProperty("server.port"))
.isEqualTo("8080");
assertThat(context.getEnvironment().getProperty("server.compression.enabled"))
.isEqualTo("true");
});
}@Test
void testSystemPropertiesWithReturn() {
Integer port = TestPropertyValues
.of("test.server.port=9090")
.applyToSystemProperties(() -> {
String portStr = System.getProperty("test.server.port");
return Integer.parseInt(portStr);
});
assertThat(port).isEqualTo(9090);
assertThat(System.getProperty("test.server.port")).isNull();
}@Test
void testOverrideProperties() {
new ApplicationContextRunner()
.withPropertyValues("app.mode=production")
.run(context -> {
// Original property
assertThat(context.getEnvironment().getProperty("app.mode"))
.isEqualTo("production");
// Override with test value
TestPropertyValues
.of("app.mode=test")
.applyTo(context.getEnvironment());
assertThat(context.getEnvironment().getProperty("app.mode"))
.isEqualTo("test");
});
}@Test
void testMultiplePropertySets() {
TestPropertyValues baseProps = TestPropertyValues.of(
"app.name=TestApp",
"app.version=1.0.0"
);
TestPropertyValues dbProps = TestPropertyValues.of(
"spring.datasource.url=jdbc:h2:mem:test",
"spring.datasource.driver-class-name=org.h2.Driver"
);
TestPropertyValues cacheProps = TestPropertyValues.of(
"spring.cache.type=simple",
"spring.cache.cache-names=users,products"
);
new ApplicationContextRunner()
.run(context -> {
baseProps.applyTo(context);
dbProps.applyTo(context);
cacheProps.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.name"))
.isEqualTo("TestApp");
assertThat(context.getEnvironment().getProperty("spring.datasource.url"))
.contains("h2:mem:test");
assertThat(context.getEnvironment().getProperty("spring.cache.type"))
.isEqualTo("simple");
});
}@Test
void testEnvironmentSpecificProperties() {
TestPropertyValues testEnv = TestPropertyValues.of(
"spring.profiles.active=test",
"logging.level.root=DEBUG",
"spring.jpa.show-sql=true"
);
new ApplicationContextRunner()
.withUserConfiguration(AppConfig.class)
.run(context -> {
testEnv.applyTo(context);
assertThat(context.getEnvironment().getActiveProfiles())
.contains("test");
assertThat(context.getEnvironment().getProperty("logging.level.root"))
.isEqualTo("DEBUG");
});
}@Test
void testWithSystemEnvironmentType() {
new ApplicationContextRunner()
.run(context -> {
TestPropertyValues
.of("MY_ENV_VAR=value")
.applyTo(
context.getEnvironment(),
TestPropertyValues.Type.SYSTEM_ENVIRONMENT,
"test-env-props"
);
assertThat(context.getEnvironment().getProperty("MY_ENV_VAR"))
.isEqualTo("value");
});
}
@Test
void testWithMapType() {
new ApplicationContextRunner()
.run(context -> {
TestPropertyValues
.of("my.property=value")
.applyTo(
context.getEnvironment(),
TestPropertyValues.Type.MAP,
"test-map-props"
);
assertThat(context.getEnvironment().getProperty("my.property"))
.isEqualTo("value");
});
}@ConfigurationProperties(prefix = "app")
class AppProperties {
private String name;
private int timeout;
private boolean enabled;
// getters and setters
}
@Configuration
@EnableConfigurationProperties(AppProperties.class)
class AppConfig {}
@Test
void testConfigurationPropertiesBinding() {
new ApplicationContextRunner()
.withUserConfiguration(AppConfig.class)
.run(context -> {
TestPropertyValues
.of(
"app.name=TestApplication",
"app.timeout=5000",
"app.enabled=true"
)
.applyTo(context.getEnvironment());
AppProperties props = context.getBean(AppProperties.class);
assertThat(props.getName()).isEqualTo("TestApplication");
assertThat(props.getTimeout()).isEqualTo(5000);
assertThat(props.isEnabled()).isTrue();
});
}@Test
void testNestedProperties() {
TestPropertyValues props = TestPropertyValues.of(
"server.tomcat.threads.max=200",
"server.tomcat.threads.min=10",
"server.tomcat.max-connections=10000",
"server.tomcat.accept-count=100"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("server.tomcat.threads.max"))
.isEqualTo("200");
assertThat(context.getEnvironment().getProperty("server.tomcat.max-connections"))
.isEqualTo("10000");
});
}@Test
void testListProperties() {
TestPropertyValues props = TestPropertyValues.of(
"app.allowed-origins[0]=http://localhost:3000",
"app.allowed-origins[1]=http://localhost:4200",
"app.allowed-origins[2]=https://example.com"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.allowed-origins[0]"))
.isEqualTo("http://localhost:3000");
assertThat(context.getEnvironment().getProperty("app.allowed-origins[2]"))
.isEqualTo("https://example.com");
});
}@Test
void testTypedProperties() {
TestPropertyValues props = TestPropertyValues.of(
"feature.enabled=true",
"cache.size=1024",
"retry.max-attempts=3",
"timeout.seconds=30.5"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("feature.enabled", Boolean.class))
.isTrue();
assertThat(context.getEnvironment().getProperty("cache.size", Integer.class))
.isEqualTo(1024);
assertThat(context.getEnvironment().getProperty("timeout.seconds", Double.class))
.isEqualTo(30.5);
});
}@Test
void testEmptyAndNullValues() {
TestPropertyValues props = TestPropertyValues.of(
"empty.property=",
"whitespace.property= ",
"normal.property=value"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("empty.property"))
.isEmpty();
assertThat(context.getEnvironment().getProperty("whitespace.property"))
.isEqualTo(" ");
assertThat(context.getEnvironment().getProperty("normal.property"))
.isEqualTo("value");
});
}@Test
void testUrlAndPathProperties() {
TestPropertyValues props = TestPropertyValues.of(
"app.api.base-url=https://api.example.com/v1",
"app.file.upload-dir=/tmp/uploads",
"app.jdbc.url=jdbc:postgresql://localhost:5432/testdb"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.api.base-url"))
.startsWith("https://");
assertThat(context.getEnvironment().getProperty("app.file.upload-dir"))
.isEqualTo("/tmp/uploads");
});
}@Test
void testProfileSpecificProperties() {
TestPropertyValues devProps = TestPropertyValues.of(
"spring.profiles.active=dev",
"logging.level.root=DEBUG",
"spring.h2.console.enabled=true"
);
TestPropertyValues prodProps = TestPropertyValues.of(
"spring.profiles.active=prod",
"logging.level.root=WARN",
"spring.h2.console.enabled=false"
);
// Test dev profile
new ApplicationContextRunner()
.run(context -> {
devProps.applyTo(context);
assertThat(context.getEnvironment().getProperty("spring.h2.console.enabled"))
.isEqualTo("true");
});
// Test prod profile
new ApplicationContextRunner()
.run(context -> {
prodProps.applyTo(context);
assertThat(context.getEnvironment().getProperty("spring.h2.console.enabled"))
.isEqualTo("false");
});
}@Test
void testFromStream() {
List<String> configKeys = List.of("key1", "key2", "key3");
TestPropertyValues props = TestPropertyValues.of(
configKeys.stream()
.map(key -> key + "=value-" + key)
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("key1"))
.isEqualTo("value-key1");
assertThat(context.getEnvironment().getProperty("key3"))
.isEqualTo("value-key3");
});
}// Define a configuration object
record ServerConfig(String host, int port, String protocol) {}
@Test
void testStreamWithMapper() {
List<ServerConfig> servers = List.of(
new ServerConfig("localhost", 8080, "http"),
new ServerConfig("api.example.com", 443, "https")
);
// Map objects to properties using custom mapper
TestPropertyValues props = TestPropertyValues.of(
servers.stream(),
server -> TestPropertyValues.Pair.of(
"server." + server.host() + ".port",
String.valueOf(server.port())
)
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("server.localhost.port"))
.isEqualTo("8080");
assertThat(context.getEnvironment().getProperty("server.api.example.com.port"))
.isEqualTo("443");
});
}
@Test
void testStreamAndWithMapper() {
// Build properties dynamically from different sources
Map<String, String> baseConfig = Map.of("app.name", "TestApp");
List<String> features = List.of("auth", "cache", "metrics");
TestPropertyValues props = TestPropertyValues.of(baseConfig)
.and(features.stream(), feature ->
TestPropertyValues.Pair.of("feature." + feature + ".enabled", "true")
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.name"))
.isEqualTo("TestApp");
assertThat(context.getEnvironment().getProperty("feature.auth.enabled"))
.isEqualTo("true");
assertThat(context.getEnvironment().getProperty("feature.cache.enabled"))
.isEqualTo("true");
});
}@SpringBootTest
@TestPropertySource(properties = {
"base.property=base-value"
})
class CombinedPropertiesTest {
@Autowired
private ConfigurableApplicationContext context;
@Test
void testCombinedProperties() {
// Add test-specific properties
TestPropertyValues
.of("additional.property=additional-value")
.applyTo(context);
assertThat(context.getEnvironment().getProperty("base.property"))
.isEqualTo("base-value");
assertThat(context.getEnvironment().getProperty("additional.property"))
.isEqualTo("additional-value");
}
}class ReusablePropertySets {
static final TestPropertyValues H2_DATABASE = TestPropertyValues.of(
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.datasource.driverClassName=org.h2.Driver",
"spring.jpa.database-platform=org.hibernate.dialect.H2Dialect"
);
static final TestPropertyValues REDIS_CACHE = TestPropertyValues.of(
"spring.cache.type=redis",
"spring.redis.host=localhost",
"spring.redis.port=6379"
);
static final TestPropertyValues DEBUG_LOGGING = TestPropertyValues.of(
"logging.level.root=DEBUG",
"logging.level.org.springframework=DEBUG"
);
}
@Test
void testWithReusableProperties() {
new ApplicationContextRunner()
.run(context -> {
ReusablePropertySets.H2_DATABASE.applyTo(context);
ReusablePropertySets.DEBUG_LOGGING.applyTo(context);
assertThat(context.getEnvironment().getProperty("spring.datasource.url"))
.contains("h2:mem");
assertThat(context.getEnvironment().getProperty("logging.level.root"))
.isEqualTo("DEBUG");
});
}@Test
void testSpecialCharacters() {
TestPropertyValues props = TestPropertyValues.of(
"app.message=Hello, World!",
"app.regex=\\d{3}-\\d{4}",
"app.json={\"key\":\"value\"}"
);
new ApplicationContextRunner()
.run(context -> {
props.applyTo(context);
assertThat(context.getEnvironment().getProperty("app.message"))
.contains("Hello");
assertThat(context.getEnvironment().getProperty("app.regex"))
.contains("\\d{3}");
});
}Full Package: org.springframework.boot.test.util.ApplicationContextTestUtils
Utility for application context lifecycle management in tests.
public abstract class ApplicationContextTestUtils {
/**
* Closes this ApplicationContext and its parent hierarchy if any
* Recursively closes parent contexts up the hierarchy
* Safe to call with null context
* @param context the context to close (can be null)
* @since 1.4.0
*/
public static void closeAll(@Nullable ApplicationContext context);
}import org.springframework.boot.test.util.ApplicationContextTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Test
void testCloseContextHierarchy() {
// Create parent context
ConfigurableApplicationContext parent =
new AnnotationConfigApplicationContext(ParentConfig.class);
// Create child context
ConfigurableApplicationContext child =
new AnnotationConfigApplicationContext();
child.setParent(parent);
child.register(ChildConfig.class);
child.refresh();
// Close entire hierarchy (child and parent)
ApplicationContextTestUtils.closeAll(child);
assertThat(child.isActive()).isFalse();
assertThat(parent.isActive()).isFalse();
}Issue: Properties not applied
Issue: Property format error