CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

90

Quality

90%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

This version of the tile failed moderation
Moderation pipeline encountered an internal error
Overview
Quality
Evals
Security
Files

advanced-examples.mdplugins/developer-kit-java/skills/unit-test-config-properties/references/

Advanced ConfigurationProperties Testing Examples

Nested Configuration Properties

Complex Property Structure

@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

@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

@ConfigurationProperties(prefix = "app.feature-flags")
@Data
public class FeatureFlagProperties {
  private Map<String, Boolean> flags = new HashMap<>();
  private Map<String, FeatureConfig> features = new HashMap<>();

  @Data
  public static class FeatureConfig {
    private boolean enabled;
    private String description;
    private List<String> allowedUsers;
  }
}

class MapPropertiesTest {

  @Test
  void shouldBindSimpleBooleanMap() {
    new ApplicationContextRunner()
      .withPropertyValues(
        "app.feature-flags.flags.dark-mode=true",
        "app.feature-flags.flags.beta-features=false"
      )
      .withBean(FeatureFlagProperties.class)
      .run(context -> {
        FeatureFlagProperties props = context.getBean(FeatureFlagProperties.class);
        assertThat(props.getFlags()).containsEntry("dark-mode", true);
        assertThat(props.getFlags()).containsEntry("beta-features", false);
      });
  }

  @Test
  void shouldBindNestedMapStructures() {
    new ApplicationContextRunner()
      .withPropertyValues(
        "app.feature-flags.features.payment.enabled=true",
        "app.feature-flags.features.payment.description=Payment module",
        "app.feature-flags.features.payment.allowedUsers[0]=admin",
        "app.feature-flags.features.payment.allowedUsers[1]=finance"
      )
      .withBean(FeatureFlagProperties.class)
      .run(context -> {
        FeatureFlagProperties props = context.getBean(FeatureFlagProperties.class);
        FeatureFlagProperties.FeatureConfig payment = props.getFeatures().get("payment");
        assertThat(payment.isEnabled()).isTrue();
        assertThat(payment.getDescription()).isEqualTo("Payment module");
        assertThat(payment.getAllowedUsers()).containsExactly("admin", "finance");
      });
  }
}

Default Values Testing

@ConfigurationProperties(prefix = "app.cache")
@Data
public class CacheProperties {
  private long ttlSeconds = 300;
  private int maxSize = 1000;
  private boolean enabled = true;
  private String cacheType = "IN_MEMORY";
}

class DefaultValuesTest {

  @Test
  void shouldUseDefaultValuesWhenNotSpecified() {
    new ApplicationContextRunner()
      .withBean(CacheProperties.class)
      .run(context -> {
        CacheProperties props = context.getBean(CacheProperties.class);
        assertThat(props.getTtlSeconds()).isEqualTo(300L);
        assertThat(props.getMaxSize()).isEqualTo(1000);
        assertThat(props.isEnabled()).isTrue();
        assertThat(props.getCacheType()).isEqualTo("IN_MEMORY");
      });
  }

  @Test
  void shouldOverrideDefaultValuesWithProvidedProperties() {
    new ApplicationContextRunner()
      .withPropertyValues(
        "app.cache.ttlSeconds=600",
        "app.cache.cacheType=REDIS"
      )
      .withBean(CacheProperties.class)
      .run(context -> {
        CacheProperties props = context.getBean(CacheProperties.class);
        assertThat(props.getTtlSeconds()).isEqualTo(600L);
        assertThat(props.getCacheType()).isEqualTo("REDIS");
        assertThat(props.getMaxSize()).isEqualTo(1000); // Default unchanged
      });
  }
}

DataSize and Duration Advanced Patterns

@ConfigurationProperties(prefix = "app.upload")
@Data
public class UploadProperties {
  private DataSize maxFileSize = DataSize.ofMegabytes(10);
  private DataSize maxTotalSize = DataSize.ofGigabytes(1);
  private Duration timeout = Duration.ofSeconds(30);
  private List<DataSize> allowedExtensions;
}

class DataSizeDurationTest {

  @Test
  void shouldConvertVariousDurationFormats() {
    new ApplicationContextRunner()
      .withPropertyValues(
        "app.upload.timeout=2h30m",
        "app.upload.maxFileSize=25MB",
        "app.upload.maxTotalSize=5GB"
      )
      .withBean(UploadProperties.class)
      .run(context -> {
        UploadProperties props = context.getBean(UploadProperties.class);
        assertThat(props.getTimeout()).isEqualTo(Duration.ofHours(2).plusMinutes(30));
        assertThat(props.getMaxFileSize()).isEqualTo(DataSize.ofMegabytes(25));
        assertThat(props.getMaxTotalSize()).isEqualTo(DataSize.ofGigabytes(5));
      });
  }

  @Test
  void shouldHandleIsoDurationFormat() {
    new ApplicationContextRunner()
      .withPropertyValues("app.upload.timeout=PT1H30M")
      .withBean(UploadProperties.class)
      .run(context -> {
        assertThat(context.getBean(UploadProperties.class).getTimeout())
          .isEqualTo(Duration.ofHours(1).plusMinutes(30));
      });
  }
}

References

  • Spring Boot ConfigurationProperties
  • ApplicationContextRunner Testing
  • Spring Boot Validation
  • Relaxed Binding

plugins

developer-kit-java

skills

unit-test-config-properties

README.md

CHANGELOG.md

context7.json

CONTRIBUTING.md

README_CN.md

README_ES.md

README_IT.md

README.md

tessl.json

tile.json