How do you point Gradle at a TestNG suite XML file, and when would you prefer suite-XML-driven discovery over Gradle's class detection?
answer
- useTestNG { suites(file(...)) }
- XML controls ordering / parallel / packages
- suite-driven replaces class scan
- one source of truth, don't split
- varargs / multiple suites compose
basics
~10 sInside useTestNG { } call suites(file("src/test/resources/testng.xml")). Gradle then runs the tests listed in that XML, letting TestNG control ordering, grouping, and parallel config instead of Gradle's own class scan.
solid answer
~40 sTestNG can define an entire run in a `testng.xml` suite file — which classes/packages run, in what order, with which groups, listeners, and parallel mode. To use it from Gradle, call `suites(...)` inside the `useTestNG { }` closure, passing one or more `File`s (typically via `file("src/test/resources/testng.xml")`). When suites are supplied, TestNG's suite-driven discovery takes over from Gradle's default class detection: only what the XML references runs, and the XML's `parallel`, `thread-count`, group filters, and method ordering are honored. You prefer suite XML when you need declarative, version-controlled run definitions shared across IDE and build, complex inter-test dependencies, or fine-grained parallelism that's awkward to express in the Gradle DSL. The trade-off is two sources of truth, so teams usually pick one model and stay with it.
code
kotlin · 8 linestasks.named<Test>("test") {
useTestNG {
suites(
file("src/test/resources/testng-smoke.xml"),
file("src/test/resources/testng-regression.xml"),
)
}
}go deeper
Know that suites(file(...)) inside useTestNG points Gradle at a testng.xml.
Contrast class detection vs suite-driven discovery and list what the XML controls (ordering, parallel, packages).
Discuss single-source-of-truth, composing multiple suites, and caching/input-tracking implications.
Decide the org-wide model — declarative suite XML for shared CI/IDE parity vs DSL simplicity — and standardize it.
## Two discovery models With TestNG, Gradle can find tests in two ways: 1. **Class detection (default):** Gradle scans compiled test classes for TestNG annotations and runs everything it finds, applying any `includeGroups`/`excludeGroups` you set. 2. **Suite-XML driven:** You hand Gradle one or more `testng.xml` files and TestNG itself decides what runs based on the `<suite>`/`<test>`/`<classes>`/`<packages>` declarations. ## Wiring a suite file ```kotlin tasks.named<Test>("test") { useTestNG { suites(file("src/test/resources/testng.xml")) } } ``` `suites(...)` accepts varargs / multiple calls, so you can compose several XML files. A minimal suite: ```xml <!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd"> <suite name="smoke" parallel="methods" thread-count="4"> <test name="login"> <groups><run><include name="smoke"/></run></groups> <classes> <class name="com.example.LoginTest"/> </classes> </test> </suite> ``` ## What the XML controls that the DSL doesn't (as cleanly) - **Ordering & dependencies** between `<test>` blocks. - **Parallel granularity** — `parallel="methods|classes|tests|instances"` plus `thread-count`. - **Package-level inclusion** via `<packages>`. - **Per-suite listeners and parameters** (`<parameter>` entries injected via `@Parameters`). ## When to choose which Prefer **suite XML** when: the run definition must be declarative and version-controlled, shared identically between the IDE and CI, expresses complex group/dependency logic, or needs nuanced parallelism. Prefer **class detection** when: the project is straightforward, you want zero extra files, and Gradle-side `includeGroups`/parallel options suffice. ## The caveat: don't split the brain If you supply suite XML *and* set overlapping Gradle options (groups, parallelism), reasoning about the effective run gets hard because two configs interact. Pick one as the source of truth. Most teams that adopt suite XML push all selection into the XML and keep the Gradle block to just `suites(...)`. ## Caching note The suite XML is an input to the `Test` task's behavior; ensure it lives under a tracked source set (e.g. `src/test/resources`) so changes correctly invalidate up-to-date checks and the build cache.
- If you supply a suite XML, does Gradle still scan all annotated classes?No — suite-driven discovery takes over; only the classes/packages the XML references are run, with the XML's group and parallel settings applied.
- Why is it risky to set includeGroups in Gradle AND group filters in the suite XML?You end up with two interacting sources of truth, making the effective test set hard to reason about. Keep selection in one place.
- Where should the testng.xml live so caching stays correct?Under a tracked source set such as src/test/resources, so edits invalidate the Test task's up-to-date checks and cache entry.
saying these in an interview costs you the question
- Thinking suites(...) merges with class detection rather than replacing it for what runs.
- Placing testng.xml outside any source set, breaking up-to-date checks.
- Maintaining group selection in both the DSL and the XML simultaneously.