100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Data-Driven Testing

Learn how to separate test logic from input data in Selenium frameworks using TestNG's @DataProvider and JUnit 5's @ParameterizedTest.

Test Framework IntegrationIntermediate8 min readJul 10, 2026
Analogies

Data-Driven Testing

Data-driven testing is the practice of separating test logic from test input values, so a single test method executes repeatedly against many different datasets — different username/password combinations, different search terms, different form inputs — instead of writing a near-duplicate test method for every value. In Selenium frameworks this is essential because UI flows like login, registration, or checkout genuinely need to be verified against many boundary and equivalence-class inputs (valid credentials, invalid password, locked account, empty field), and hardcoding a separate test per case would balloon maintenance cost every time a locator or flow step changes.

🏏

Cricket analogy: A bowling machine runs a batsman through the same cover-drive technique against dozens of different deliveries (varying pace, line, and length) rather than facing one ball; data-driven testing runs one test method against dozens of different data rows the same way.

TestNG DataProvider

TestNG's @DataProvider annotation is the most common way to implement data-driven testing in Java Selenium frameworks: a method annotated @DataProvider(name = "loginData") returns an Object[][] where each inner array is one row of parameters, and a @Test method declares matching parameters plus dataProvider = "loginData" to have TestNG invoke it once per row automatically, reporting each invocation as a separate result in the report. Setting the parallel attribute on @DataProvider (parallel = true) lets TestNG execute those data-driven invocations concurrently across threads, which matters when a data set has dozens of rows and each row drives a full Selenium browser session.

🏏

Cricket analogy: A net session bowling machine is loaded with a sequence of deliveries (yorker, bouncer, googly) and the batsman faces each one in turn with the same stance and technique; @DataProvider loads a sequence of data rows that the same @Test method faces one after another.

java
// LoginDataProviderTest.java
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.Assert;

public class LoginDataProviderTest {

    @DataProvider(name = "loginData", parallel = true)
    public Object[][] loginData() {
        return new Object[][] {
            { "qa_user",   "Secr3t!",   true  },
            { "qa_user",   "wrongpass", false },
            { "locked_usr","Secr3t!",   false },
            { "",          "Secr3t!",   false },
        };
    }

    @Test(dataProvider = "loginData")
    public void loginAttempt(String username, String password, boolean expectedSuccess) {
        LoginPage loginPage = new LoginPage(driver);
        loginPage.enterCredentials(username, password);
        loginPage.clickLogin();
        Assert.assertEquals(loginPage.isLoggedIn(), expectedSuccess,
            "Mismatch for user: " + username);
    }
}

// Reading from CSV with a data provider (Apache Commons CSV)
@DataProvider(name = "csvLoginData")
public Object[][] csvLoginData() throws IOException {
    List<CSVRecord> records = CSVParser.parse(
        new File("src/test/resources/login_data.csv"),
        StandardCharsets.UTF_8, CSVFormat.DEFAULT.withFirstRecordAsHeader())
        .getRecords();
    Object[][] data = new Object[records.size()][2];
    for (int i = 0; i < records.size(); i++) {
        data[i][0] = records.get(i).get("username");
        data[i][1] = records.get(i).get("password");
    }
    return data;
}

Keep data-driven test data external to the test code (CSV, Excel via Apache POI, JSON via Jackson, or a database) whenever the dataset is large or maintained by non-developers (like a QA analyst updating a spreadsheet of test credentials). Reserve inline Object[][] data providers for small, stable datasets that rarely change, since they require a code change and recompile to update.

JUnit 5 Parameterized Tests

JUnit 5 achieves the same goal through @ParameterizedTest combined with a data source annotation: @ValueSource for a simple list of one type, @CsvSource for inline comma-separated rows, @CsvFileSource to point at an external CSV file, or @MethodSource to reference a static factory method returning a Stream of Arguments — closely mirroring TestNG's @DataProvider but expressed through JUnit 5's more granular, purpose-specific annotations rather than one general-purpose mechanism.

🏏

Cricket analogy: A fielding drill uses different specific setups for catching practice (high catches), for slip cordon reflexes, and for run-out drills, each a purpose-built drill rather than one generic fielding exercise; JUnit 5's specific annotations (@CsvSource, @MethodSource) are those purpose-built variants versus TestNG's one general @DataProvider.

  • Data-driven testing separates test logic from input data so one test method runs against many datasets without code duplication.
  • TestNG implements this via @DataProvider, returning Object[][] rows consumed by @Test methods declaring matching parameters.
  • @DataProvider(parallel = true) lets data-driven test invocations run concurrently across threads for large datasets.
  • External data sources (CSV via Apache Commons CSV, Excel via Apache POI, JSON via Jackson) are preferred for large or non-developer-maintained datasets.
  • JUnit 5 achieves the same pattern via @ParameterizedTest with @ValueSource, @CsvSource, @CsvFileSource, or @MethodSource.
  • Each row of test data typically maps to boundary and equivalence-class values (valid, invalid, empty, locked) for thorough coverage.
  • Keeping data external avoids recompiling test code every time input values need to change.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#SeleniumStudyNotes#TestingQA#DataDrivenTesting#Data#Driven#TestNG#DataProvider#StudyNotes#SkillVeris