
Unit Test Config Properties
Unit-test Spring Boot `@ConfigurationProperties` bindings with `ApplicationContextRunner` instead of spinning up a full app context.
Overview
unit-test-config-properties is an agent skill for the Build phase that shows how to unit-test Spring `@ConfigurationProperties` with `ApplicationContextRunner` and property overrides.
Install
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-config-propertiesWhat is this skill?
- Examples for nested `@ConfigurationProperties` (pool settings, replica lists) with dotted `withPropertyValues` keys
- Uses Spring Boot `ApplicationContextRunner` for fast, slice-style context tests without a web layer
- Covers list binding, default nested objects, and assertion patterns with AssertJ-style checks
- Maps externalized config prefixes (`app.database.*`) to typed Java beans under test
Adoption & trust: 1.2k installs on skills.sh; 271 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You changed `application.yml` or profile-specific properties but have no fast test proving nested config still maps to your Java beans.
Who is it for?
Indie developers maintaining Spring Boot services who externalize database and pool settings and want slice tests without `@SpringBootTest` overhead.
Skip if: Teams not on Spring Boot, pure frontend apps, or repos where configuration is only validated manually in staging.
When should I use this skill?
Adding or refactoring `@ConfigurationProperties` classes and you need fast tests that prove property keys bind correctly.
What do I get? / Deliverables
You get runnable test templates that bind dotted property keys to nested types and lists, so config regressions fail in CI before production.
- ApplicationContextRunner test classes with `withPropertyValues` scenarios
- Assertions on nested objects and collection-bound replicas
Recommended Skills
Journey fit
Backend configuration binding is exercised while the product is still being built and wired, before release hardening. Nested POJOs, lists, and profile overrides are core backend wiring concerns in Java/Spring services.
How it compares
Use instead of full integration tests when you only need to verify property binding, not HTTP or JPA behavior.
Common Questions / FAQ
Who is unit-test-config-properties for?
Solo and small-team Java builders using Spring Boot who ship APIs and keep sensitive connection settings in externalized configuration.
When should I use unit-test-config-properties?
During Build when adding nested config POJOs, replica lists, or pool defaults; before Ship when tightening CI around profile-specific YAML.
Is unit-test-config-properties safe to install?
It is documentation and example patterns only; review the Security Audits panel on this catalog page before enabling any third-party skill in your agent.
SKILL.md
READMESKILL.md - Unit Test Config Properties
# Advanced ConfigurationProperties Testing Examples ## Nested Configuration Properties ### Complex Property Structure ```java @ConfigurationProperties(prefix = "app.database") @Data public class DatabaseProperties { private String url; private String username; private Pool pool = new Pool(); private List<Replica> replicas = new ArrayList<>(); @Data public static class Pool { private int maxSize = 10; private int minIdle = 5; private long connectionTimeout = 30000; } @Data public static class Replica { private String name; private String url; private int priority; } } class NestedPropertiesTest { @Test void shouldBindNestedProperties() { new ApplicationContextRunner() .withPropertyValues( "app.database.url=jdbc:mysql://localhost/db", "app.database.username=admin", "app.database.pool.maxSize=20", "app.database.pool.minIdle=10", "app.database.pool.connectionTimeout=60000" ) .withBean(DatabaseProperties.class) .run(context -> { DatabaseProperties props = context.getBean(DatabaseProperties.class); assertThat(props.getUrl()).isEqualTo("jdbc:mysql://localhost/db"); assertThat(props.getPool().getMaxSize()).isEqualTo(20); assertThat(props.getPool().getConnectionTimeout()).isEqualTo(60000L); }); } @Test void shouldBindListOfReplicas() { new ApplicationContextRunner() .withPropertyValues( "app.database.replicas[0].name=replica-1", "app.database.replicas[0].url=jdbc:mysql://replica1/db", "app.database.replicas[0].priority=1", "app.database.replicas[1].name=replica-2", "app.database.replicas[1].url=jdbc:mysql://replica2/db", "app.database.replicas[1].priority=2" ) .withBean(DatabaseProperties.class) .run(context -> { DatabaseProperties props = context.getBean(DatabaseProperties.class); assertThat(props.getReplicas()).hasSize(2); assertThat(props.getReplicas().get(0).getName()).isEqualTo("replica-1"); assertThat(props.getReplicas().get(1).getPriority()).isEqualTo(2); }); } } ``` ## Profile-Specific Configurations ### Environment-Specific Properties ```java @Configuration @Profile("prod") class ProductionConfiguration { @Bean public SecurityProperties securityProperties() { SecurityProperties props = new SecurityProperties(); props.setEnableTwoFactor(true); props.setMaxLoginAttempts(3); return props; } } @Configuration @Profile("dev") class DevelopmentConfiguration { @Bean public SecurityProperties securityProperties() { SecurityProperties props = new SecurityProperties(); props.setEnableTwoFactor(false); props.setMaxLoginAttempts(999); return props; } } class ProfileBasedConfigurationTest { @Test void shouldLoadProductionConfiguration() { new ApplicationContextRunner() .withPropertyValues("spring.profiles.active=prod") .withUserConfiguration(ProductionConfiguration.class) .run(context -> { SecurityProperties props = context.getBean(SecurityProperties.class); assertThat(props.isEnableTwoFactor()).isTrue(); assertThat(props.getMaxLoginAttempts()).isEqualTo(3); }); } @Test void shouldLoadDevelopmentConfiguration() { new ApplicationContextRunner() .withPropertyValues("spring.profiles.active=dev") .withUserConfiguration(DevelopmentConfiguration.class) .run(context -> { SecurityProperties props = context.getBean(SecurityProperties.class); assertThat(props.isEnableTwoFactor()).isFalse(); assertThat(props.getMaxLoginAttempts()).isEqualTo(999); }); } } ``` ## Map-Based Properties ```java @ConfigurationProperties(prefix = "app.feature-flags") @Data public class FeatureFlagProperties { private Map<String, Boolean> flags = new HashMap<>(); private Map<String, FeatureConfig> features = new HashMap<>();