skip to content

Test Properties & Arguments

Tests can override configuration with inline properties, pass command-line style arguments, and register values computed at runtime. Interviewers care because these overrides also change the context cache key.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What does the `properties = {}` attribute of `@SpringBootTest` do, and when would you use it?

level: juniorimportance: must knowfreq 70%

answer

  1. key=value inlined into Environment
  2. same as @TestPropertySource(properties=...)
  3. overrides application.properties
  4. must be compile-time constant
  5. part of context-cache key

basics

~10 s

It sets configuration properties just for that test, in key=value form. Those values override the same keys from application.properties, so you can test the app under specific config without editing real files.

solid answer

~40 s

`@SpringBootTest(properties = {"app.retries=3", "spring.jpa.show-sql=true"})` injects inlined properties into the test's `Environment` before the context starts. Each entry is a `key=value` string; they behave exactly like `@TestPropertySource(properties = ...)` and take precedence over `application.properties`, OS environment variables, and system properties. Use it to flip a feature flag, point at an in-memory value, disable a scheduler, or exercise a config branch for one test class — without touching real config files or profiles. Because the value is baked into the annotation it changes the context configuration, so tests with different `properties` get separate (non-cached) application contexts. For values only known at runtime (a container's random port) you need `@DynamicPropertySource` instead, since annotation attributes must be compile-time constants.

code

java · 15 lines
java
@SpringBootTest(properties = {
    "app.feature.new-checkout=true",
    "spring.jpa.show-sql=false",
    "spring.main.banner-mode=off"
})
class CheckoutServiceTest {

    @Value("${app.feature.new-checkout}")
    boolean newCheckoutEnabled;

    @Test
    void flagIsHonored() {
        assertThat(newCheckoutEnabled).isTrue();
    }
}

go deeper

for a junior

Know it sets key=value overrides scoped to the test and beats application.properties.

for a middle

Explain it maps to inlined test properties and must be compile-time constants.

for a senior

Discuss precedence vs other sources and the context-caching cost of differing arrays.

for a principal

Frame it within the full property-source ordering and when to prefer profiles/@DynamicPropertySource for maintainability.

## What it is `@SpringBootTest` is the annotation that boots a full Spring `ApplicationContext` for an integration test. Its `properties` attribute accepts an array of `String` in `key=value` format: ```java @SpringBootTest(properties = { "app.feature.new-checkout=true", "spring.task.scheduling.pool.size=1" }) ``` Spring adds these as an **inlined test property source** to the `Environment` (the object that resolves `@Value`, `@ConfigurationProperties`, and `environment.getProperty(...)`). This is functionally identical to `@TestPropertySource(properties = {...})` — under the hood `@SpringBootTest#properties` is documented as an alias-like mechanism that contributes inlined properties. ## Why it exists You often need a bean to behave differently in a test: a shorter timeout, a disabled background job, a feature flag on. Editing `src/main/resources/application.properties` would change production behavior; a test-only profile file is heavier. `properties = {}` scopes the override to a single test class, right next to the code that relies on it. ## Precedence Inlined test properties sit near the top of Spring Boot's property-source ordering — above `application.properties`, OS environment variables, Java system properties, and command-line args. So `properties = {"server.port=0"}` reliably wins. (The only things above it are `@TestPropertySource` and `@DynamicPropertySource`.) ## Gotchas - **Values must be compile-time constants.** You cannot write `"db.url=" + container.getJdbcUrl()` because annotations require constant expressions. Runtime values need `@DynamicPropertySource`. - **Context caching.** Spring caches the `ApplicationContext` keyed by its configuration, and `properties` is part of that key. Two test classes with different `properties` arrays get two contexts — more startup cost. Reusing identical `properties` lets them share a cached context. - **Format.** Use `key=value`, one entry per array element. `key: value` (YAML style) does **not** work here; it's flat properties syntax. You *can* reference placeholders and use `spring.config.import` style keys, but each element is a single property. - **`spring.main.*` and framework keys work too**, e.g. `properties = {"spring.main.banner-mode=off"}`. ## When to use Static, known-at-compile-time overrides for one test class: feature flags, pool sizes, toggling `show-sql`, disabling a scheduler. For dynamic values use `@DynamicPropertySource`; for loading a whole file use `@TestPropertySource(locations=...)` or a test profile.

  • Why can't you put `container.getJdbcUrl()` in `properties = {}`?
    Annotation attributes must be compile-time constant expressions, but a container URL is only known at runtime. Use `@DynamicPropertySource` with a static method and a `Supplier` for runtime values.
  • Do two test classes with different `properties` share a cached context?
    No. The `properties` array is part of the context-cache key, so differing values force separate `ApplicationContext` instances, increasing startup cost.

saying these in an interview costs you the question

  • Thinking `properties` edits or reads the real `application.properties` file
  • Believing you can inline runtime values like a container URL
  • Using YAML `key: value` syntax instead of flat `key=value`
  • Assuming it never affects context caching

context

open as a page

What is `@DynamicPropertySource` for, and how does it interact with `@TestPropertySource` / `@SpringBootTest(properties=...)`?

level: seniorimportance: must knowfreq 55%

basics

~10 s

@DynamicPropertySource registers properties whose values are only known at runtime — like a Testcontainers JDBC URL — via a static method taking a DynamicPropertyRegistry. Its values have the highest precedence, above @TestPropertySource and @SpringBootTest(properties).

open as a page

What does the `args = {}` attribute of `@SpringBootTest` do, and how do those values reach the application?

level: middleimportance: should knowfreq 40%

basics

~10 s

args is the String[] passed to SpringApplication.run(args), exactly like real command-line arguments. Option args like --app.mode=fast become properties; you can also inject the whole ApplicationArguments bean to read them.

open as a page

How does `@TestPropertySource` work, and how do its `locations` and inlined `properties` relate to `@SpringBootTest(properties=...)`?

level: middleimportance: should knowfreq 45%

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.

open as a page

Lay out the property-source precedence across `@DynamicPropertySource`, `@TestPropertySource`, `@SpringBootTest(properties)`, `args`, and application config — and explain how `spring.main.*` overrides fit in.

level: principalimportance: should knowfreq 30%

basics

~10 s

Highest to lowest in a test: @DynamicPropertySource > @TestPropertySource/@SpringBootTest(properties) > command-line args > system properties/env > application.properties. spring.main.* keys configure SpringApplication itself and can be set through any of these, so precedence still applies.

open as a page