Spring Boot
testing
@Value
placeholder error
exception handling

Value Could not resolve placeholder in Spring Boot Test

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The Could not resolve placeholder 'some.property' in value "${some.property}" error in Spring Boot tests means the @Value annotation references a property that is not defined in any property source available to the test context. This happens because test classes use a separate application context that may not load the same property files as the main application. The fix is to provide the property through @TestPropertySource, application-test.properties, or @SpringBootTest(properties = ...).

The Error

java
1@SpringBootTest
2class UserServiceTest {
3
4    @Value("${app.api.key}")
5    private String apiKey;
6
7    @Test
8    void testSomething() {
9        // Never reaches here
10    }
11}
12// java.lang.IllegalStateException: Could not resolve placeholder
13// 'app.api.key' in value "${app.api.key}"

The test context cannot find app.api.key in any loaded property file.

Provide test-specific properties directly on the test class:

java
1@SpringBootTest
2@TestPropertySource(properties = {
3    "app.api.key=test-key-12345",
4    "app.base.url=http://localhost:8080"
5})
6class UserServiceTest {
7
8    @Value("${app.api.key}")
9    private String apiKey;  // "test-key-12345"
10
11    @Test
12    void testApiKey() {
13        assertEquals("test-key-12345", apiKey);
14    }
15}

Properties defined in @TestPropertySource override all other sources, making them ideal for test isolation.

Fix 2: Test Properties File

Create src/test/resources/application-test.properties:

properties
1# src/test/resources/application-test.properties
2app.api.key=test-key-12345
3app.base.url=http://localhost:8080
4app.timeout=5000
java
1@SpringBootTest
2@ActiveProfiles("test")
3class UserServiceTest {
4
5    @Value("${app.api.key}")
6    private String apiKey;  // Loaded from application-test.properties
7}

Or use src/test/resources/application.properties (no profile) to override the main application properties for all tests.

Fix 3: @SpringBootTest properties

java
1@SpringBootTest(properties = {
2    "app.api.key=inline-test-key",
3    "app.feature.enabled=true"
4})
5class UserServiceTest {
6
7    @Value("${app.api.key}")
8    private String apiKey;  // "inline-test-key"
9}

This is equivalent to @TestPropertySource(properties = ...) but defined on @SpringBootTest itself.

Fix 4: Default Values in @Value

Provide a fallback so the annotation never fails:

java
1@Value("${app.api.key:default-key}")
2private String apiKey;  // Uses "default-key" if property is missing
3
4@Value("${app.timeout:30000}")
5private int timeout;  // Uses 30000 if property is missing
6
7@Value("${app.feature.enabled:false}")
8private boolean featureEnabled;  // Uses false if property is missing

The syntax is ${property.name:defaultValue}. The colon separates the property name from the default.

Fix 5: Test Application Properties

Place a file at src/test/resources/application.properties:

properties
# This overrides src/main/resources/application.properties for all tests
app.api.key=test-value
app.database.url=jdbc:h2:mem:testdb

Spring Boot's test resource classpath takes priority over main resources.

Understanding Property Source Priority

From highest to lowest priority in tests:

 
11. @TestPropertySource(properties = {...})
22. @SpringBootTest(properties = {...})
33. @TestPropertySource(locations = "classpath:custom.properties")
44. System properties (-Dproperty=value)
55. src/test/resources/application-{profile}.properties
66. src/test/resources/application.properties
77. src/main/resources/application-{profile}.properties
88. src/main/resources/application.properties

Common Scenarios

Missing Environment Variable

java
1// application.properties
2# app.secret=${SECRET_KEY}requires SECRET_KEY env variable
3
4// In test, provide it:
5@TestPropertySource(properties = "app.secret=test-secret")
6class MyTest { ... }

Properties from External Config Server

java
1// Production loads from Spring Cloud Config Server
2// Tests should not depend on external services
3
4@SpringBootTest
5@TestPropertySource(properties = {
6    "spring.cloud.config.enabled=false",
7    "app.remote.property=test-value"
8})
9class MyTest { ... }

YAML Properties

If using application.yml, create src/test/resources/application-test.yml:

yaml
1app:
2  api:
3    key: test-key-12345
4  base:
5    url: http://localhost:8080
java
@SpringBootTest
@ActiveProfiles("test")
class MyTest { ... }

Slice Tests (@WebMvcTest, @DataJpaTest)

Slice tests load only part of the context, which often means fewer properties are available:

java
1@WebMvcTest(UserController.class)
2@TestPropertySource(properties = "app.api.key=test-key")
3class UserControllerTest {
4
5    @Autowired
6    private MockMvc mockMvc;
7
8    @Test
9    void testEndpoint() throws Exception {
10        mockMvc.perform(get("/api/users"))
11            .andExpect(status().isOk());
12    }
13}

Always provide necessary properties explicitly in slice tests since they do not load the full application context.

Using @MockBean to Avoid Property Issues

If the property is only used by a bean you do not need in the test, mock the bean:

java
1@WebMvcTest(UserController.class)
2class UserControllerTest {
3
4    @MockBean
5    private ExternalApiClient apiClient;
6    // ExternalApiClient uses @Value("${app.api.key}")
7    // But since it's mocked, the property is never resolved
8
9    @Autowired
10    private MockMvc mockMvc;
11}

Common Pitfalls

  • Typos in property names: @Value("${app.api-key}") vs app.api.key in properties file. Spring Boot relaxed binding converts api-key to api.key, but @Value does NOT use relaxed binding. Use @ConfigurationProperties for relaxed binding support.
  • Wrong properties file location: src/test/resources/application.properties is correct. src/test/application.properties (missing resources/) is ignored.
  • Profile not activated: application-test.properties requires @ActiveProfiles("test"). Without it, Spring only loads application.properties.
  • SpEL confusion: @Value("#{systemProperties['user.home']}") uses SpEL (Spring Expression Language, with #). @Value("${app.key}") uses property placeholder (with $). Mixing them up causes different errors.
  • Properties in @Configuration classes: If a @Configuration class uses @Value and is loaded in the test context, you must provide those properties even if your test does not directly use them.

Summary

  • Use @TestPropertySource(properties = {"key=value"}) for test-specific property overrides
  • Create src/test/resources/application-test.properties with @ActiveProfiles("test") for shared test properties
  • Add default values with @Value("${prop:default}") to prevent failures when properties are optional
  • Slice tests (@WebMvcTest, @DataJpaTest) load minimal context, so always provide necessary properties explicitly
  • Use @MockBean to avoid resolving properties for beans you do not need in the test

Course illustration
Course illustration

All Rights Reserved.