unit-test-config-properties
giuseppe-trisciuoglio/developer-kit
Unit test Spring Boot @ConfigurationProperties with property binding, validation, and type conversion patterns.
What is unit-test-config-properties?
Provides patterns for testing @ConfigurationProperties classes using @ConfigurationPropertiesTest and ApplicationContextRunner. Validates property binding, tests validation constraints, verifies default values, checks type conversions, and mocks property sources without full Spring context startup. Use when testing application configuration binding, YAML/properties files, environment-specific settings, or nested property structures.
- Test property binding and name mapping with ApplicationContextRunner
- Validate @Validated constraints (@NotBlank, @Min, @Max, @Email, @Positive)
- Verify default values and fallback behavior
- Test type conversions for Duration, DataSize, collections, and maps
- Test nested property structures and collection binding
- Test profile-specific configurations for different environments
How to install unit-test-config-properties
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-config-properties- spring-boot-starter-test dependency
- spring-boot-configuration-processor dependency
- AssertJ for assertions
- JUnit 5
How to use unit-test-config-properties
- 1.Add spring-boot-starter-test, spring-boot-configuration-processor, and assertj-core to test dependencies
- 2.Create a test class for your @ConfigurationProperties class
- 3.Use ApplicationContextRunner to load properties without full Spring context
- 4.Call withPropertyValues() to set test property values matching your prefix
- 5.Call withBean() to register the @ConfigurationProperties class
- 6.Use run(context -> {...}) to assert property values and validation behavior
- 7.Test validation by checking context.hasFailed() for invalid configurations
- 8.Test type conversions by providing Duration (30s), DataSize (50MB), and collection values
Use cases
- Testing JWT secret and security configuration properties with validation
- Validating server host/port and thread pool configuration constraints
- Testing cache expiry Duration and file upload DataSize conversions
- Verifying feature flags and environment-specific property lists
- Testing nested database connection properties with validation
- Spring Boot developers testing configuration classes
- Backend engineers validating application.properties and YAML configurations
- QA engineers verifying environment-specific settings
- Developers building configuration-driven applications
unit-test-config-properties FAQ
Check that the @ConfigurationProperties prefix matches your test property paths exactly. Spring uses kebab-case to camelCase conversion, so app.my-property maps to myProperty. Verify the property names in withPropertyValues() match this pattern.
Add @Validated to your @ConfigurationProperties class, then use context.hasFailed() to verify invalid values are rejected. For example, set a blank host value and assert context.hasFailed().getFailure().hasMessageContaining('host').
Yes, ApplicationContextRunner is designed for fast context-free testing. It loads only the beans you specify, avoiding full application startup and making tests run quickly.
Provide string values in the format Spring expects: Duration as '30s', '5m', etc.; DataSize as '50MB', '1GB', etc. ApplicationContextRunner will automatically convert these to the correct types.
Use @Profile annotations on your @ConfigurationProperties classes and test each profile separately by creating different ApplicationContextRunner instances with different property values for each environment.
Full instructions (SKILL.md)
Source of truth, from giuseppe-trisciuoglio/developer-kit.
name: unit-test-config-properties
description: Provides patterns for unit testing @ConfigurationProperties classes with @ConfigurationPropertiesTest. Validates property binding, tests validation constraints, verifies default values, checks type conversions, and mocks property sources for Spring Boot configuration properties. Use when testing application configuration binding, validating YAML or application.properties files, verifying environment-specific settings, or testing nested property structures.
allowed-tools: Read, Write, Bash, Glob, Grep
Unit Testing Configuration Properties and Profiles
Overview
This skill provides patterns for unit testing @ConfigurationProperties bindings, environment-specific configurations, and property validation using JUnit 5. Covers testing property name mapping, type conversions, validation constraints, nested structures, and profile-specific configurations without full Spring context startup.
Key validation checkpoints:
- Property prefix matches between
@ConfigurationPropertiesand test properties - Validation triggers on
@Validatedclasses with invalid values - Type conversions work for Duration, DataSize, collections, and maps
When to Use
- Testing
@ConfigurationPropertiesproperty binding - Testing property name mapping and type conversions
- Validating configuration with
@NotBlank,@Min,@Max,@Emailconstraints - Testing environment-specific configurations (dev, prod)
- Testing nested property structures and collections
- Verifying default values when properties are not specified
- Fast configuration tests without Spring context startup
Instructions
- Set up test dependencies: Add
spring-boot-starter-testand AssertJ dependencies - Use ApplicationContextRunner: Test property bindings without starting full Spring context
- Define property prefixes: Ensure
@ConfigurationProperties(prefix = "...")matches test property paths - Test all property paths: Verify each property including nested structures and collections
- Test validation constraints: Use
context.hasFailed()to verify@Validatedproperties reject invalid values - Test type conversions: Verify Duration (
30s), DataSize (50MB), collections, and maps convert correctly - Test default values: Verify properties have correct defaults when not specified in test properties
- Test profile-specific configs: Use
@ProfilewithApplicationContextRunnerfor environment-specific configurations - Test edge cases: Include empty strings, null values, and type mismatches
Troubleshooting flow:
- If properties don't bind → Check prefix matches (kebab-case to camelCase conversion)
- If validation doesn't trigger → Verify
@Validatedannotation is present - If context fails to start → Check dependencies and
@ConfigurationPropertiesclass structure
Examples
Setup: Test Dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
Basic Pattern: Property Binding
@ConfigurationProperties(prefix = "app.security")
@Data
public class SecurityProperties {
private String jwtSecret;
private long jwtExpirationMs;
private int maxLoginAttempts;
private boolean enableTwoFactor;
}
class SecurityPropertiesTest {
@Test
void shouldBindPropertiesFromEnvironment() {
new ApplicationContextRunner()
.withPropertyValues(
"app.security.jwtSecret=my-secret-key",
"app.security.jwtExpirationMs=3600000",
"app.security.maxLoginAttempts=5",
"app.security.enableTwoFactor=true"
)
.withBean(SecurityProperties.class)
.run(context -> {
SecurityProperties props = context.getBean(SecurityProperties.class);
assertThat(props.getJwtSecret()).isEqualTo("my-secret-key");
assertThat(props.getJwtExpirationMs()).isEqualTo(3600000L);
assertThat(props.getMaxLoginAttempts()).isEqualTo(5);
assertThat(props.isEnableTwoFactor()).isTrue();
});
}
@Test
void shouldUseDefaultValuesWhenPropertiesNotProvided() {
new ApplicationContextRunner()
.withPropertyValues("app.security.jwtSecret=key")
.withBean(SecurityProperties.class)
.run(context -> {
SecurityProperties props = context.getBean(SecurityProperties.class);
assertThat(props.getJwtSecret()).isEqualTo("key");
assertThat(props.getMaxLoginAttempts()).isZero();
});
}
}
Validation Testing
@ConfigurationProperties(prefix = "app.server")
@Data
@Validated
public class ServerProperties {
@NotBlank
private String host;
@Min(1)
@Max(65535)
private int port = 8080;
@Positive
private int threadPoolSize;
}
class ConfigurationValidationTest {
@Test
void shouldFailValidationWhenHostIsBlank() {
new ApplicationContextRunner()
.withPropertyValues(
"app.server.host=",
"app.server.port=8080",
"app.server.threadPoolSize=10"
)
.withBean(ServerProperties.class)
.run(context -> {
assertThat(context).hasFailed()
.getFailure()
.hasMessageContaining("host");
});
}
@Test
void shouldPassValidationWithValidConfiguration() {
new ApplicationContextRunner()
.withPropertyValues(
"app.server.host=localhost",
"app.server.port=8080",
"app.server.threadPoolSize=10"
)
.withBean(ServerProperties.class)
.run(context -> {
assertThat(context).hasNotFailed();
assertThat(context.getBean(ServerProperties.class).getHost()).isEqualTo("localhost");
});
}
}
Type Conversion Testing
@ConfigurationProperties(prefix = "app.features")
@Data
public class FeatureProperties {
private Duration cacheExpiry = Duration.ofMinutes(10);
private DataSize maxUploadSize = DataSize.ofMegabytes(100);
private List<String> enabledFeatures;
private Map<String, String> featureFlags;
}
class TypeConversionTest {
@Test
void shouldConvertDurationFromString() {
new ApplicationContextRunner()
.withPropertyValues("app.features.cacheExpiry=30s")
.withBean(FeatureProperties.class)
.run(context -> {
assertThat(context.getBean(FeatureProperties.class).getCacheExpiry())
.isEqualTo(Duration.ofSeconds(30));
});
}
@Test
void shouldConvertCommaDelimitedList() {
new ApplicationContextRunner()
.withPropertyValues("app.features.enabledFeatures=feature1,feature2")
.withBean(FeatureProperties.class)
.run(context -> {
assertThat(context.getBean(FeatureProperties.class).getEnabledFeatures())
.containsExactly("feature1", "feature2");
});
}
}
For nested properties, profile-specific configurations, collection binding, and advanced validation patterns, see references/advanced-examples.md.
Best Practices
- Test all property bindings including nested structures and collections
- Test validation constraints for all
@NotBlank,@Min,@Max,@Email,@Positiveannotations - Test both default and custom values to verify fallback behavior
- Use ApplicationContextRunner for fast context-free testing
- Test profile-specific configurations separately with
@Profile - Verify type conversions for Duration, DataSize, collections, and maps
- Test edge cases: empty strings, null values, type mismatches, out-of-range values
Constraints and Warnings
- Kebab-case to camelCase: Property
app.my-propertymaps tomyPropertyin Java - Loose binding: Spring Boot uses loose binding by default; use strict binding if needed
@Validatedrequired: Add@Validatedannotation to enable constraint validation@ConstructorBinding: All parameters must be bindable when using constructor binding- List indexing: Use
[0],[1]notation; ensure sequential indexing for lists - Duration format: Accepts ISO-8601 (
PT30S) or simple syntax (30s,1m,2h) - Context isolation: Each
ApplicationContextRunnercreates a new context with no shared state - Profile activation: Use
spring.profiles.active=profileNameinwithPropertyValues()for profile tests
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Properties not binding | Prefix mismatch | Verify @ConfigurationProperties(prefix="...") matches property paths |
| Validation not triggered | Missing @Validated | Add @Validated annotation to configuration class |
| Context fails to start | Missing dependencies | Ensure spring-boot-starter-test is in test scope |
| Nested properties null | Inner class missing | Use @Data on nested classes or provide getters/setters |
| Collection binding fails | Wrong indexing | Use [0], [1] notation, not (0), (1) |
Related skills
More from giuseppe-trisciuoglio/developer-kit and the wider catalog.

unit-test-controller-layer
Unit test REST controllers in isolation using MockMvc and @WebMvcTest patterns.

unit-test-exception-handler
Unit test patterns for Spring Boot @ExceptionHandler and @ControllerAdvice with MockMvc

unit-test-json-serialization
Unit test JSON serialization/deserialization with Spring's @JsonTest and Jackson patterns.

unit-test-mapper-converter
Unit testing patterns for MapStruct mappers and custom converters with null handling and nested object validation.

unit-test-parameterized
Data-driven unit tests with JUnit 5 @ParameterizedTest, @ValueSource, @CsvSource, @MethodSource.

unit-test-scheduled-async
Unit test Spring @Scheduled and @Async methods with JUnit 5, Awaitility, and Mockito without waiting for real scheduling intervals.