What does the `args = {}` attribute of `@SpringBootTest` do, and how do those values reach the application?
answer
- String[] into SpringApplication.run
- --key=value → commandLineArgs property source
- non-option args only via ApplicationArguments
- drives CommandLineRunner/ApplicationRunner
- lower precedence than properties={}
basics
~10 sargs 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.
solid answer
~40 s`@SpringBootTest(args = {"--app.mode=fast", "import", "file.csv"})` simulates launching the app from the command line: the array is handed to `SpringApplication.run(args)`. Two things happen. First, **option arguments** (`--key=value`) are exposed as a `commandLineArgs` property source, so `@Value("${app.mode}")` resolves to `fast`. Second, Spring registers an `ApplicationArguments` bean you can `@Autowired` to inspect both option args (`getOptionValues("app.mode")`) and **non-option args** (`getNonOptionArgs()` → `[import, file.csv]`). This is the way to test `CommandLineRunner`/`ApplicationRunner` beans and any startup logic that branches on arguments. Note the command-line property source has lower precedence than `@SpringBootTest(properties=...)` and `@TestPropertySource`, so those can still override an option arg. Non-option args are *not* properties — they're only visible through `ApplicationArguments`.
code
java · 15 lines@SpringBootTest(args = {"--app.mode=fast", "import", "users.csv"})
class StartupArgsTest {
@Autowired ApplicationArguments args;
@Value("${app.mode}")
String mode; // resolved from the option arg
@Test
void argumentsAreParsed() {
assertThat(mode).isEqualTo("fast");
assertThat(args.getOptionValues("app.mode")).containsExactly("fast");
assertThat(args.getNonOptionArgs()).containsExactly("import", "users.csv");
}
}go deeper
Know args is the String[] passed to main/SpringApplication.run.
Distinguish option vs non-option args and how each is accessed.
Explain precedence of the command-line source and how it drives runners.
Reason about add-command-line-properties, testing CLI entrypoints, and when args vs properties is the right tool.
## What it is `args` supplies the `String[]` that a Spring Boot app would normally receive on the command line. `@SpringBootTest` passes it into `SpringApplication.run(...)`, so the test reproduces a real CLI launch. ```java @SpringBootTest(args = {"--app.mode=fast", "--app.retries=2", "import", "users.csv"}) ``` ## Two kinds of arguments Spring Boot classifies each element: - **Option arguments** start with `--` and look like `--key=value` (or bare `--flag`). These are parsed into a property source named `commandLineArgs` and become resolvable properties: `@Value("${app.mode}")`, `environment.getProperty("app.retries")`, `@ConfigurationProperties` binding. - **Non-option arguments** are everything else (`import`, `users.csv`). They are **not** properties. They are only reachable via the `ApplicationArguments` bean. ## ApplicationArguments Spring Boot registers a singleton `ApplicationArguments` bean built from `args`. Inject it to inspect the raw arguments: ```java @Autowired ApplicationArguments appArgs; // appArgs.getOptionNames() -> [app.mode, app.retries] // appArgs.getOptionValues("app.mode") -> [fast] // appArgs.getNonOptionArgs() -> [import, users.csv] // appArgs.containsOption("app.mode") -> true ``` `CommandLineRunner#run(String... args)` receives the raw array; `ApplicationRunner#run(ApplicationArguments args)` receives the parsed object — both are exercised when the context starts, so `args` is how you drive them in a test. ## Precedence The `commandLineArgs` property source is high, but **below** `@SpringBootTest(properties=...)` and `@TestPropertySource`. Ordering (highest first, test-relevant slice): `@DynamicPropertySource` > `@TestPropertySource` > `@SpringBootTest(properties)` > command-line args (`args`) > system properties > OS env > `application.properties`. So an option arg overrides `application.properties`, but an inlined `properties` entry overrides the option arg. ## Gotchas - **Non-option args aren't properties.** `getNonOptionArgs()` is the only way to see `import`/`users.csv`; `@Value("${import}")` will not resolve. - **`addCommandLineProperties`.** By default `SpringApplication.setAddCommandLineProperties(true)`, so option args become a property source. If an app disabled it (`spring.main.add-command-line-properties=false`), option args stop feeding the Environment but `ApplicationArguments` still holds them. - **Format matters.** `--key value` (space) is a *non-option* argument pair, not a property; use `--key=value` for a property. - **Web tests.** With `webEnvironment=RANDOM_PORT` the app still starts via `run(args)`, so `args` are honored the same way. ## When to use Testing `CommandLineRunner`/`ApplicationRunner`, batch/CLI entrypoints, or any bean whose behavior depends on how the process was launched. For plain config overrides prefer `properties = {}` — it's clearer and higher precedence.
- Can you read `import` (a non-option arg) via `@Value("${import}")`?No. Non-option arguments never become properties; they're only accessible through `ApplicationArguments.getNonOptionArgs()` or the raw `String...` in a `CommandLineRunner`.
- If `application.properties` sets `app.mode=slow` and args pass `--app.mode=fast`, which wins?`fast`. Command-line option args have higher precedence than `application.properties`. But an inlined `@SpringBootTest(properties="app.mode=x")` would override even the arg.
saying these in an interview costs you the question
- Claiming non-option args are exposed as properties
- Saying `args` has higher precedence than `properties={}`
- Not knowing `ApplicationArguments` is an injectable bean
- Using `--key value` and expecting it to bind as a property