How do @ActiveProfiles and @TestPropertySource work together, and when would you choose one over the other?
answer
- Profiles = which beans/files; property source = what values
- Orthogonal, often combined
- @TestPropertySource beats application-<profile>.properties
- Structural swap -> profile; few tweaks -> properties
- Both affect the cache key
basics
~20 sThey solve different problems: @ActiveProfiles picks WHICH beans/config files are active; @TestPropertySource sets WHAT property values apply. Use profiles to swap wiring (mock vs real beans, a profile file); use @TestPropertySource to override individual property values. They combine freely.
solid answer
~40 s@ActiveProfiles activates bean-definition profiles: it turns @Profile-guarded beans on/off and, in Boot, loads application-<profile>.properties. @TestPropertySource layers property values onto the Environment, overriding application property files. They're orthogonal and commonly used together on the same test class. Reach for @ActiveProfiles when the difference is structural — you need a different set of beans, a different datasource wiring, or a whole profile-specific config file. Reach for @TestPropertySource when you only need to tweak a handful of values — flip a feature flag, shrink a timeout, point at a test URL. A key ordering fact when combined: the @TestPropertySource source ranks above the profile-specific file, so an inlined value overrides the same key from application-<profile>.properties even while that profile is active.
code
kotlin · 12 lines@SpringBootTest
@ActiveProfiles("test") // swaps in @Profile("test") beans + application-test.properties
@TestPropertySource(properties = ["app.retries=0", "app.feature.beta=true"])
class CheckoutServiceTest {
@Value("\${app.retries}") var retries: Int = -1
@Test
fun `inlined value overrides the profile file`() {
assertThat(retries).isEqualTo(0) // beats app.retries in application-test.properties
}
}go deeper
Know profiles pick beans/files, @TestPropertySource sets values.
Choose the right tool and know they combine with inlined-over-profile-file precedence.
Explain the Environment ordering and cache-key consequences of combining them.
Standardize profile+property bundles across the suite to control both correctness and context caching.
## Two orthogonal levers - **`@ActiveProfiles`** answers *which configuration is in play*: it activates named **bean-definition profiles**, so `@Profile("x")` beans are created and, with Spring Boot, `application-x.properties`/`.yml` is loaded. It's about **wiring and which files load**. - **`@TestPropertySource`** answers *what values are in effect*: it inserts a high-precedence property source (from `locations` and/or inlined `properties`) into the `Environment`. It's about **property values**, and it doesn't create or remove beans. Because they operate on different axes, they're frequently combined: ```java @SpringBootTest @ActiveProfiles("test") // loads application-test.properties, @Profile("test") beans @TestPropertySource(properties = "app.retries=0") // tweak one value on top class CheckoutTest { } ``` ## Choosing between them - **Use `@ActiveProfiles`** when the change is **structural**: swap a real external client for a stub bean, choose an embedded vs. real datasource, or pull in a curated `application-<profile>.properties` full of related settings. Good when many settings/beans move together and you want to name that bundle. - **Use `@TestPropertySource`** when you need to **override a few discrete values**: flip a boolean feature flag, set a short timeout, override a URL. Cheaper and more local than defining a whole profile. - **Combine** when you want a profile's wiring **plus** a per-test value tweak. ## Precedence when combined The `@TestPropertySource` source sits **above** `application-<profile>.properties` in the `Environment` ordering. So if the `test` profile file sets `app.retries=3` and you inline `app.retries=0`, the effective value is `0`. Profiles decide which files load; `@TestPropertySource` still wins the value fight against those files. ## Caching note Both are part of the context cache key, so each distinct profile set or inlined-property set can fork a new cached context — prefer shared, standardized combinations across a suite. ## Common mistakes - Trying to use `@ActiveProfiles` to set a value (it doesn't set arbitrary properties — only activates profiles/profile files). - Trying to use `@TestPropertySource` to switch beans (it changes values, not which `@Profile` beans exist). - Forgetting that inlined properties override the profile file when both are present.
- Can @TestPropertySource activate a profile?Not directly by intent, but you could inline spring.profiles.active=foo as a property; that's discouraged — use @ActiveProfiles, which is purpose-built and participates cleanly in the cache key and profile resolution.
- If application-test.properties and an inlined property both set the same key, which wins?The inlined @TestPropertySource value — its source ranks above the profile-specific file in the Environment.
saying these in an interview costs you the question
- Saying @ActiveProfiles sets property values
- Saying @TestPropertySource swaps @Profile beans
- Assuming the profile file overrides inlined properties