How does `@TestPropertySource` work, and how do its `locations` and inlined `properties` relate to `@SpringBootTest(properties=...)`?
answer
- locations = files, properties = inlined
- inlined beats locations
- @SpringBootTest(properties) == inlined @TestPropertySource
- no locations attr on @SpringBootTest
- locations can't load YAML
basics
~10 s@TestPropertySource adds test-only property sources: locations loads .properties files, and properties inlines key=value pairs. Inlined properties beat locations, and both override application.properties. @SpringBootTest(properties=...) is essentially the same inlined mechanism.
solid answer
~40 s`@TestPropertySource` is a Spring TestContext annotation that contributes property sources to a test's `Environment`. `locations = {"classpath:test.properties"}` loads resource files; `properties = {"a=1"}` inlines pairs. When both are present, **inlined `properties` take precedence over `locations`**, and the whole `@TestPropertySource` source outranks `application.properties`, system properties, and OS env. `@SpringBootTest(properties=...)` writes into the same inlined-properties channel, so semantically they're equivalent for the inlined case — `@SpringBootTest` just saves you a second annotation. Use `@TestPropertySource(locations=...)` when you want a reusable file of test config; use inlined `properties` (on either annotation) for a handful of one-off overrides. Both are compile-time-only, so for runtime values you still need `@DynamicPropertySource`, which sits above `@TestPropertySource` in precedence.
code
java · 15 lines@SpringBootTest
@TestPropertySource(
locations = "classpath:test-overrides.properties", // app.retries=1 here
properties = "app.retries=5" // inlined wins -> 5
)
class RetryConfigTest {
@Value("${app.retries}")
int retries;
@Test
void inlinedBeatsFile() {
assertThat(retries).isEqualTo(5);
}
}go deeper
Know locations = files, properties = inlined pairs, both test-scoped.
Explain inlined-beats-locations and equivalence to @SpringBootTest(properties).
Cover full precedence, YAML limitation, and inheritance/merging semantics.
Weigh files vs inlined vs profiles vs dynamic for maintainable, cache-friendly test config.
## What it is `@TestPropertySource` is part of the Spring TestContext Framework (not Boot-specific — it works with plain `@ContextConfiguration` too). It registers **test-scoped property sources** high in the `Environment` so they override application config during a test. ```java @TestPropertySource( locations = {"classpath:test-overrides.properties"}, properties = {"app.retries=5", "app.cache.enabled=false"} ) ``` ## Two channels - **`locations`** — resource paths (`classpath:`, `file:`) to `.properties`/`.xml` property files. If omitted, Spring can detect a default `<TestClass>.properties` next to the test class. - **`properties`** (inlined) — `key=value` strings baked into the annotation. **Internal precedence:** inlined `properties` are added *after* `locations`, so **inlined wins** when a key appears in both. ## Relationship to `@SpringBootTest(properties=...)` Spring Boot's `@SpringBootTest#properties` feeds the **same inlined test-property mechanism**. So these two are equivalent: ```java @SpringBootTest(properties = {"a=1"}) // vs @SpringBootTest @TestPropertySource(properties = {"a=1"}) ``` `@SpringBootTest` merely offers the attribute inline for convenience. If you need `locations` (a file), you still reach for `@TestPropertySource` because `@SpringBootTest` has no `locations` attribute. ## Overall precedence (test slice, highest first) 1. `@DynamicPropertySource` 2. `@TestPropertySource` inlined `properties` (and `@SpringBootTest(properties)`) 3. `@TestPropertySource` `locations` 4. command-line `args` 5. Java system properties / OS environment 6. `application.properties` / `application.yml` ## Gotchas - **Merging & inheritance.** By default a subclass's `@TestPropertySource` *merges* with the superclass's (inheritance is on). `inheritLocations`/`inheritProperties = false` disables that. - **Empty annotation.** A bare `@TestPropertySource` with neither attribute triggers detection of the default `<TestClass>.properties` file; if that file is missing you get an error. - **YAML not supported by `locations`.** `@TestPropertySource(locations=...)` cannot load `.yml` files (no `PropertySourceFactory` for YAML by default). Use `.properties`, a `factory`, or a `@Profile`/`spring.config.import`. - **Cache key.** Like `properties`, `@TestPropertySource` is part of the context-cache key; differing values fork the cached context. - **Compile-time only.** Both channels require static values; runtime values need `@DynamicPropertySource`. ## When to use which - Reusable, larger config set shared across tests → `@TestPropertySource(locations="classpath:...")` or a test profile. - A few targeted overrides → inlined `properties` on either annotation. - Runtime-derived values (containers, random ports) → `@DynamicPropertySource`.
- If a key is defined both in `locations` and inlined `properties`, which value applies?The inlined `properties` value. Inlined properties are registered with higher precedence than the resource files named in `locations`.
- Can `@TestPropertySource(locations=...)` load an `application-test.yml`?Not by default — there's no built-in YAML `PropertySourceFactory`. Use a `.properties` file, supply a custom `factory`, or activate a test profile instead.
saying these in an interview costs you the question
- Saying `locations` overrides inlined `properties`
- Thinking `@SpringBootTest` has a `locations` attribute
- Assuming `@TestPropertySource(locations)` loads YAML
- Not knowing subclass property sources merge by default