Q25 of 37 · Selenium

How do you parameterise tests with TestNG data providers?

SeleniumMidseleniumtestngdata-drivenparametrise

Short answer

Short answer: Annotate a method with `@DataProvider(name = "...")` returning `Object[][]` — each row is one test invocation. Reference it with `@Test(dataProvider = "...")`. TestNG runs the test once per row, with isolated reporting per case.

Detail

Data providers turn a single test method into N parametrised invocations — each row of the returned 2D array becomes the arguments for one run. They're TestNG's answer to JUnit 5's @ParameterizedTest.

The basic shape:

public class LoginTest {
    @DataProvider(name = "loginCases")
    public Object[][] loginCases() {
        return new Object[][] {
            { "valid@example.com", "secret123",  true,  null },
            { "wrong@example.com", "secret123",  false, "User not found" },
            { "valid@example.com", "wrongpass",  false, "Incorrect password" },
            { "",                  "secret123",  false, "Email is required" },
        };
    }

    @Test(dataProvider = "loginCases")
    public void login(String email, String password,
                      boolean shouldSucceed, String expectedError) {
        new LoginPage(driver).loginAs(email, password);
        if (shouldSucceed) {
            assertTrue(new DashboardPage(driver).isLoaded());
        } else {
            assertEquals(new LoginPage(driver).errorText(), expectedError);
        }
    }
}

Reporting: TestNG names each invocation (login[0], login[1], …) so failures show which row failed. You can override naming with ITestContext for human-readable cases.

Sources for data providers:

  • Inline arrays — fine for small fixed sets.
  • CSV / Excel / JSON files — read in the data provider method. Useful for QA-owned test data.
  • External classes@DataProvider(name = "users", class = TestData.class).
  • Database fetches — pull canonical test cases from a shared store.

Refinements:

  • parallel = true runs the rows concurrently — combined with thread-safe page objects, you get test-level parallelism for free.
  • A data provider can return Iterator<Object[]> to lazily generate rows for very large sets.

Common mistake: making the data provider too granular. If the test has 200 rows, ask whether you really want 200 separate test reports — often a few well-chosen equivalence-partition rows are clearer than exhaustive data.

// WHAT INTERVIEWERS LOOK FOR

The Object[][] shape, knowing parallel = true exists, awareness that external data sources (CSV/JSON/DB) plug into providers, and the wisdom of choosing a few good rows over exhaustive sets.

// COMMON PITFALL

Using a data provider to compensate for not understanding equivalence partitioning — running 50 rows that all exercise the same partition adds runtime without adding coverage.