When you run `./gradlew test` in a multi-project build, how is that different from running `./gradlew :app:test`? Explain unqualified task names versus fully qualified task paths.
answer
- unqualified = name match across subprojects
- qualified `:app:test` = exactly one task
- leading colon anchors at root (absolute)
- cwd scopes unqualified matching
- CI -> qualified paths
basics
~10 sAn unqualified name like test runs the task in every project that has it (within the current project and its subprojects). A qualified path like :app:test targets exactly one project's task.
solid answer
~50 sA **task selector** can be unqualified (`test`) or fully qualified with a path (`:app:test`). - **Unqualified** (`./gradlew test`): Gradle treats it as a *name match* across the current project **and all its subprojects**. Every project that has a task named `test` is selected, so in a multi-project build you may trigger many `test` tasks at once. - **Qualified** (`./gradlew :app:test`): the leading colon means "from the root," so `:app:test` resolves to exactly one task — the `test` task of the `:app` subproject — and nothing else. Where you invoke from matters for unqualified names: running from a subproject directory scopes the name match to that subproject and its children. Qualified paths are absolute and unaffected by your current directory. Use qualified paths in CI and scripts for deterministic, single-target execution; use unqualified names interactively when you want the aggregate behavior.
code
bash · 8 lines# Aggregate: every project's `test`
./gradlew test
# Single target, deterministic
./gradlew :app:test
# Nested subproject
./gradlew :services:billing:testgo deeper
Know that :app:test targets one project's task and a bare test can hit many.
Explain the fan-out semantics and how the current directory scopes unqualified matching.
Recommend qualified paths in CI for determinism and discuss task-path uniqueness across the tree.
Set org conventions: scripts/CI use qualified paths; reserve aggregate unqualified names for developer ergonomics, and design subproject naming so paths stay readable.
## Task selectors When you type `./gradlew <something>`, each `<something>` that isn't an option flag is a **task selector**. Gradle resolves selectors to a set of concrete task instances and then schedules them (with their dependencies) into the task graph. ## Task paths Every task in a build has a unique **path** built from project paths plus the task name, using `:` as the separator: - `:test` — the `test` task of the **root** project. - `:app:test` — the `test` task of the subproject `:app`. - `:services:billing:test` — nested subproject path. A leading `:` anchors the path at the root, so qualified paths are **absolute** and independent of your working directory. ## Unqualified vs qualified - **Unqualified name** (`test`): Gradle searches the **current project and all of its descendants** for tasks with that name and selects every match. In a build with `:app`, `:lib`, `:web` all owning a `test` task, `./gradlew test` from the root runs all three. - **Qualified path** (`:app:test`): selects exactly the one task at that path. No name-matching fan-out. ## Why the current directory matters for unqualified names Unqualified selection is relative to the **project you invoke from**. From the root, the search covers the whole tree. From inside `app/`, `./gradlew test` only matches `:app` and its children. Qualified paths ignore the current directory entirely. ```bash # From repo root ./gradlew test # runs test in EVERY project that has it ./gradlew :app:test # runs ONLY :app:test, regardless of cwd ``` ## Practical guidance For CI pipelines and automation, prefer **fully qualified paths** so a build does exactly one thing and stays stable as new subprojects are added. Interactively, unqualified names are convenient for "test everything." Note that `help --task :app:test` shows the resolved task's description and type, which is handy when a name is ambiguous.
- If two subprojects both have a `check` task, what does `./gradlew check` from the root do?It selects and runs the `check` task in every project that defines one — root plus all matching subprojects — running them all in one invocation.
- How can you make an unqualified run target only one subproject without typing the full path?`cd` into that subproject's directory and run `./gradlew <task>`; unqualified matching is scoped to the current project and its descendants.
saying these in an interview costs you the question
- Claiming `./gradlew test` only runs the root project's test task — it fans out across subprojects.
- Saying qualified paths depend on the current directory — they are absolute from the root.