skip to content

How do you include or exclude TestNG groups from Gradle, and what does that control?

level: middleimportance: should knowfreq 45%

answer

  1. includeGroups / excludeGroups
  2. @Test(groups = ...) string tags
  3. exclude wins over include
  4. parameterize via -P property
  5. smoke-on-push, full-nightly

basics

~10 s

Inside useTestNG { ... } call includeGroups("smoke") and excludeGroups("slow"). TestNG groups are named tags on @Test methods, and these options select which tagged tests run.

solid answer

~40 s

TestNG groups are arbitrary string tags declared on tests via `@Test(groups = ["smoke"])`. Gradle exposes them through `TestNGOptions` inside the `useTestNG { }` closure: `includeGroups("smoke", "regression")` runs only tests tagged with those groups, and `excludeGroups("slow", "flaky")` removes tests so tagged. Both can be combined — exclusion wins over inclusion for a test in both sets. This is the Gradle-side equivalent of TestNG's `<groups>` element in suite XML, and it lets CI pipelines run, say, only the `smoke` group on every push and the full suite nightly without changing test code. A common pattern is to read the group from a Gradle property (`-PtestGroups=smoke`) so the same build script serves multiple pipelines.

code

kotlin · 6 lines
kotlin
tasks.named<Test>("test") {
    useTestNG {
        includeGroups("smoke")
        excludeGroups("slow", "flaky")
    }
}

go deeper

for a junior

Know that includeGroups/excludeGroups exist and that groups are @Test labels.

for a middle

Explain exclude-over-include precedence and parameterizing groups via a Gradle property for CI tiers.

for a senior

Discuss layering with suite XML, avoiding split ownership of selection, and using groups as the fast-feedback lever.

for a principal

Frame group strategy as a CI architecture decision: tiered pipelines (smoke/nightly/full) driven by one parameterized build.

## What a TestNG group is A *group* is just a named label you attach to a test method or class: ```java @Test(groups = {"smoke", "login"}) public void loginWorks() { ... } ``` Groups are TestNG's primary mechanism for slicing a suite — far more flexible than JUnit 4's categories. A single method can belong to many groups, and groups can depend on other groups. ## Selecting groups from Gradle Gradle's `TestNGOptions` (the receiver of the `useTestNG { }` closure) mirrors TestNG's selection semantics: ```kotlin tasks.named<Test>("test") { useTestNG { includeGroups("smoke", "regression") excludeGroups("slow") } } ``` - **includeGroups** — only tests in at least one listed group run. If you list none, all tests are eligible. - **excludeGroups** — tests in any listed group are dropped, even if they also match an include. Exclusion takes precedence, which matters when a test carries both an included and an excluded group. ## Driving selection from the command line Hard-coding groups in the build script is rigid. The idiomatic approach is to parameterize: ```kotlin tasks.named<Test>("test") { useTestNG { val groups = (project.findProperty("testGroups") as String?)?.split(",") groups?.forEach { includeGroups(it.trim()) } } } ``` Then `./gradlew test -PtestGroups=smoke` runs only the smoke group, while a bare `./gradlew test` runs everything. CI can thus reuse one build definition across smoke/nightly/full pipelines. ## Relationship to suite XML Whatever you set here is layered with any TestNG suite XML you also supply. If a `testng.xml` already constrains `<groups>`, Gradle's options and the XML both apply; keep ownership of group selection in one place to avoid confusion. ## Why it matters for build performance Group selection is the cheapest lever for keeping fast feedback: run a tiny smoke group on every commit (seconds) and reserve the slow integration group for scheduled builds, all without recompiling or duplicating tests.

  • A test is tagged with both 'smoke' and 'slow'; you includeGroups('smoke') and excludeGroups('slow'). Does it run?
    No. Exclusion takes precedence over inclusion, so the test is filtered out.
  • How would you make the active group selectable per CI pipeline without editing the build script?
    Read a Gradle project property (e.g. -PtestGroups=smoke) inside the useTestNG closure and feed it to includeGroups, defaulting to all tests when unset.

saying these in an interview costs you the question

  • Confusing TestNG groups with JUnit 5 tags/@Tag — different APIs.
  • Assuming includeGroups and excludeGroups are mutually exclusive (they compose).
  • Saying include wins when both match — exclusion wins.

context