---
title: Suites, groups and parameters in testng.xml | TestingBot
description: 'Annotations describe individual tests. `testng.xml` describes a *run*:
  which classes take part, which groups are included, which browser to use, how many…'
source_url:
  html: https://testingbot.com/resources/courses/selenium-testng/testng-xml
  md: https://testingbot.com/resources/courses/selenium-testng/testng-xml.md
---

Course

[Selenium Java Tutorial with TestNG](https://testingbot.com/resources/courses/selenium-testng)

Chapter 7 of 11

1. [1 Selenium and TestNG: how they fit together](https://testingbot.com/resources/courses/selenium-testng)
2. [2 Set up a Maven project for Selenium](https://testingbot.com/resources/courses/selenium-testng/project-setup)
3. [3 Your first Selenium test with TestNG](https://testingbot.com/resources/courses/selenium-testng/first-test)
4. [4 TestNG annotations and the driver lifecycle](https://testingbot.com/resources/courses/selenium-testng/annotations)
5. [5 Hard assertions vs SoftAssert](https://testingbot.com/resources/courses/selenium-testng/assertions)
6. [6 Data-driven tests with DataProvider](https://testingbot.com/resources/courses/selenium-testng/data-providers)
7. [7 Suites, groups and parameters in testng.xml](https://testingbot.com/resources/courses/selenium-testng/testng-xml)
8. [8 Run Selenium tests in parallel](https://testingbot.com/resources/courses/selenium-testng/parallel-execution)
9. [9 Listeners, screenshots and reports](https://testingbot.com/resources/courses/selenium-testng/listeners-and-reports)
10. [10 Run the suite on a Selenium grid](https://testingbot.com/resources/courses/selenium-testng/run-on-a-selenium-grid)
11. [11 Knowledge check](https://testingbot.com/resources/courses/selenium-testng/knowledge-check)

[Exit course](https://testingbot.com/resources/courses)

 Chapter 7 of 11 Intermediate 7 min read 3 quick checks Updated Nov 2026 

# Suites, groups and parameters in testng.xml
On this page
1. [Anatomy of a suite file](https://testingbot.com#anatomy-of-a-suite-file)
2. [Groups](https://testingbot.com#groups)
3. [Parameters: configuration without code changes](https://testingbot.com#parameters-configuration-without-code-changes)
4. [Dependencies between tests](https://testingbot.com#dependencies-between-tests)
5. [Several suite files](https://testingbot.com#several-suite-files)

Annotations describe individual tests. `testng.xml` describes a _run_: which classes take part, which groups are included, which browser to use, how many threads, which listeners to attach. Keeping that in a file instead of in code means CI can run a smoke suite on every commit and a full regression suite nightly from the same codebase, just by pointing at a different XML file.

## Anatomy of a suite file[#](https://testingbot.com#anatomy-of-a-suite-file)

```xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Regression" verbose="1">

  <test name="Web form - Chrome">
    <parameter name="browser" value="chrome"/>
    <classes>
      <class name="com.example.FirstTest"/>
      <class name="com.example.FormDefaultsTest"/>
      <class name="com.example.WebFormDataTest"/>
    </classes>
  </test>

</suite>
```

- **`<suite>`** is the whole run. It holds suite-wide settings such as `parallel`, `thread-count` and `<listeners>`.
- **`<test>`** is a named block of classes with its own parameters and group selection. This is the level `@BeforeTest` / `@AfterTest` refer to. A suite can contain many `<test>` blocks, for example one per browser.
- **`<classes>`** lists classes explicitly. Alternatively, `<packages><package name="com.example.checkout"/></packages>` picks up every test class in a package, so new classes join the suite automatically.

Within a class you can narrow down to specific methods:

```xml
<class name="com.example.WebFormDataTest">
  <methods>
    <include name="submitsAnyText"/>
  </methods>
</class>
```

Use method-level includes for short-term debugging only; long-term, groups scale better.

## Groups[#](https://testingbot.com#groups)

Tag tests with one or more groups in the annotation:

```java
@Test(groups = "smoke")
public void formPageLoads() { ... }

@Test(groups = {"regression", "forms"})
public void formDefaults() { ... }
```

Then select them in the suite:

```xml
<test name="Smoke">
  <groups>
    <run>
      <include name="smoke"/>
      <exclude name="quarantine"/>
    </run>
  </groups>
  <packages>
    <package name="com.example"/>
  </packages>
</test>
```

Exclusion wins over inclusion, which makes a `quarantine` group a practical way to park a known-flaky test without deleting it, while the ticket to fix it is open. Keep the list short and reviewed; a quarantine group that only grows is a test suite slowly switching itself off.

Remember the rule from chapter 3: once you filter by groups, configuration methods without a matching group are skipped unless they have `alwaysRun = true`. That is why `BaseTest` uses it.

You can also pick groups from the command line. With the Surefire 3.5.x setup from chapter 1, this runs only smoke tests from the default suite file:

```bash
mvn test -Dgroups=smoke
```

A test is in both the `smoke` and `quarantine` groups. The suite includes `smoke` and excludes `quarantine`. Does it run?

 Yes, because it was included first Only on the second attempt It fails with a configuration error No, because exclusion wins over inclusion

Excluded groups override included ones, which is what makes a quarantine group work.

## Parameters: configuration without code changes[#](https://testingbot.com#parameters-configuration-without-code-changes)

`<parameter>` values flow into methods annotated with `@Parameters`. The most useful one for a Selenium suite is the browser. Update `BaseTest`:

```java
package com.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;

public abstract class BaseTest {

    private WebDriver driver;

    protected WebDriver driver() {
        return driver;
    }

    @BeforeMethod(alwaysRun = true)
    @Parameters("browser")
    public void startDriver(@Optional("chrome") String browser) {
        boolean headless = Boolean.getBoolean("headless");
        if ("firefox".equals(browser)) {
            FirefoxOptions options = new FirefoxOptions();
            if (headless) options.addArguments("-headless");
            driver = new FirefoxDriver(options);
        } else {
            ChromeOptions options = new ChromeOptions();
            if (headless) options.addArguments("--headless=new", "--window-size=1920,1080");
            driver = new ChromeDriver(options);
        }
    }

    @AfterMethod(alwaysRun = true)
    public void stopDriver() {
        if (driver != null) {
            driver.quit();
            driver = null;
        }
    }
}
```

(The `waitUpTo` helper from chapter 3 stays as it was; it is omitted here for brevity.)

`@Optional("chrome")` supplies a default when no `<parameter name="browser">` is in scope, for instance when you run a single class from the IDE or with `-Dtest`. Without it, TestNG fails the configuration method because the parameter is missing, and every test in the class is skipped.

Parameters are inherited downward: a `<parameter>` on `<suite>` applies to every `<test>` unless a `<test>` defines the same name. That gives a clean cross-browser suite:

```xml
<suite name="Cross-browser">
  <parameter name="baseUrl" value="https://www.selenium.dev/selenium/web/"/>

  <test name="Chrome">
    <parameter name="browser" value="chrome"/>
    <packages><package name="com.example"/></packages>
  </test>

  <test name="Firefox">
    <parameter name="browser" value="firefox"/>
    <packages><package name="com.example"/></packages>
  </test>
</suite>
```

Parameters are strings and are fixed when the suite starts. For secrets such as passwords or API keys, read environment variables in code (`System.getenv("TB_KEY")`) instead; suite files end up in version control and in CI logs.

Parameters and data providers solve different problems. A **parameter** configures the environment of the whole run (which browser, which base URL). A **data provider** varies the inputs of one test. If you find yourself writing a data provider that returns browser names, a `<test>` block per browser is usually clearer.

Running one test class from the IDE, every test is skipped because the `browser` parameter is missing. What makes the class runnable on its own?

 Put the browser name in a static field Declare the parameter as `@Optional("chrome") String browser` Always run through `-Dtest`

`@Optional` supplies a default when no `<parameter>` is in scope, as with an IDE run or `-Dtest`.

## Dependencies between tests[#](https://testingbot.com#dependencies-between-tests)

Sometimes a later test is pointless if an earlier one failed. `dependsOnMethods` makes that explicit:

```java
@Test
public void formPageLoads() { ... }

@Test(dependsOnMethods = "formPageLoads")
public void formDefaults() { ... }
```

If `formPageLoads` fails, `formDefaults` is reported as **skipped** , not failed, so your report shows one real failure instead of a cascade. `dependsOnGroups` does the same for whole groups (for example, everything depends on a `health` group that checks the site is up). Adding `alwaysRun = true` to the dependent test makes it run anyway but still in order.

Use dependencies to avoid noise, not to share state. If `formDefaults` relies on `formPageLoads` having navigated the browser somewhere, the two are really one test, and they will break as soon as each gets its own browser in parallel runs.

`formDefaults` has `dependsOnMethods = "formPageLoads"`, and `formPageLoads` fails. How is `formDefaults` reported?

 As failed, with the same error As passed As skipped It is run anyway and its result is reported normally

A broken dependency skips the dependent test, so the report shows one real failure instead of a cascade (unless the dependent test sets `alwaysRun = true`).

## Several suite files[#](https://testingbot.com#several-suite-files)

A typical project ends up with a few suites:

```
testng.xml full regression (default)
testng-smoke.xml smoke group only, fast feedback on every commit
testng-grid.xml cross-browser blocks for the remote grid (chapter 9)
```

Select one at run time through the `suiteXmlFile` property defined in the pom:

```bash
mvn test -DsuiteXmlFile=testng-smoke.xml
```

A suite file can also include others with `<suite-files><suite-file path="testng-smoke.xml"/></suite-files>`, which is handy for a "run everything" entry point.

If you would like your tests written as Gherkin scenarios instead, Cucumber has a TestNG runner that plugs into the same suite mechanics; the [TestNG + Cucumber guide](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) shows the setup. The [TestNG guide in our docs](https://testingbot.com/support/web-automate/selenium/java/testng) uses exactly this parameter-per-`<test>` pattern for cross-browser runs, which we will build on in chapter 9.

Next, the suite file gets the two attributes everyone wants first: `parallel` and `thread-count`.

[Previous · Chapter 6 Data-driven tests with DataProvider](https://testingbot.com/resources/courses/selenium-testng/data-providers) [Next · Chapter 8 Run Selenium tests in parallel](https://testingbot.com/resources/courses/selenium-testng/parallel-execution)

On this page

1. [Anatomy of a suite file](https://testingbot.com#anatomy-of-a-suite-file)
2. [Groups](https://testingbot.com#groups)
3. [Parameters: configuration without code changes](https://testingbot.com#parameters-configuration-without-code-changes)
4. [Dependencies between tests](https://testingbot.com#dependencies-between-tests)
5. [Several suite files](https://testingbot.com#several-suite-files)

Certification

This course has a free, hands-on certificate.

[How it works](https://testingbot.com/resources/courses/selenium-testng/certification)
