testng-data-driven

TestNG Data-Driven Testing

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "testng-data-driven" with this command: npx skills add thebushidocollective/han/thebushidocollective-han-testng-data-driven

TestNG Data-Driven Testing

Master TestNG data-driven testing including DataProviders, Factory patterns, and parameterization for comprehensive test coverage. This skill covers techniques for testing with multiple data sets efficiently.

Overview

Data-driven testing separates test logic from test data, enabling a single test method to run against multiple inputs. TestNG provides powerful features for data-driven testing through DataProviders, Factory methods, and XML parameterization.

DataProvider Basics

Simple DataProvider

import org.testng.annotations.; import static org.testng.Assert.;

public class SimpleDataProviderTest {

@DataProvider(name = "numbers")
public Object[][] provideNumbers() {
    return new Object[][] {
        {1, 2, 3},
        {4, 5, 9},
        {0, 0, 0},
        {-1, 1, 0}
    };
}

@Test(dataProvider = "numbers")
public void testAddition(int a, int b, int expected) {
    assertEquals(a + b, expected);
}

}

DataProvider with Single Values

public class SingleValueDataProviderTest {

@DataProvider(name = "validEmails")
public Object[][] provideValidEmails() {
    return new Object[][] {
        {"user@example.com"},
        {"test.user@domain.org"},
        {"admin+tag@company.co.uk"},
        {"user123@test.io"}
    };
}

@Test(dataProvider = "validEmails")
public void testValidEmail(String email) {
    assertTrue(isValidEmail(email), "Email should be valid: " + email);
}

private boolean isValidEmail(String email) {
    return email != null && email.matches("^[\\w+.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$");
}

}

Advanced DataProvider Patterns

DataProvider in Separate Class

// DataProviders class public class TestDataProviders {

@DataProvider(name = "userData")
public static Object[][] provideUserData() {
    return new Object[][] {
        {"john", "john@example.com", 25},
        {"jane", "jane@example.com", 30},
        {"bob", "bob@example.com", 22}
    };
}

@DataProvider(name = "loginCredentials")
public static Object[][] provideLoginCredentials() {
    return new Object[][] {
        {"admin", "admin123", true},
        {"user", "user456", true},
        {"invalid", "wrong", false}
    };
}

}

// Test class using external DataProvider public class UserTest {

@Test(dataProvider = "userData", dataProviderClass = TestDataProviders.class)
public void testUserCreation(String name, String email, int age) {
    User user = new User(name, email, age);
    assertNotNull(user);
    assertEquals(user.getName(), name);
    assertEquals(user.getEmail(), email);
    assertEquals(user.getAge(), age);
}

@Test(dataProvider = "loginCredentials", dataProviderClass = TestDataProviders.class)
public void testLogin(String username, String password, boolean expectedSuccess) {
    boolean result = authService.login(username, password);
    assertEquals(result, expectedSuccess);
}

}

DataProvider with Method Context

import org.testng.ITestContext; import org.testng.annotations.*; import java.lang.reflect.Method;

public class ContextAwareDataProviderTest {

@DataProvider(name = "contextAwareData")
public Object[][] provideContextAwareData(ITestContext context, Method method) {
    String testName = method.getName();
    String suiteName = context.getSuite().getName();

    System.out.println("Providing data for: " + testName + " in suite: " + suiteName);

    if (testName.contains("Admin")) {
        return new Object[][] {
            {"admin", "ADMIN_ROLE"},
            {"superadmin", "SUPER_ADMIN_ROLE"}
        };
    } else {
        return new Object[][] {
            {"user1", "USER_ROLE"},
            {"user2", "USER_ROLE"}
        };
    }
}

@Test(dataProvider = "contextAwareData")
public void testAdminAccess(String username, String role) {
    // Test admin access
}

@Test(dataProvider = "contextAwareData")
public void testUserAccess(String username, String role) {
    // Test user access
}

}

Parallel DataProvider

public class ParallelDataProviderTest {

@DataProvider(name = "parallelData", parallel = true)
public Object[][] provideParallelData() {
    return new Object[][] {
        {"Test 1"},
        {"Test 2"},
        {"Test 3"},
        {"Test 4"},
        {"Test 5"},
        {"Test 6"},
        {"Test 7"},
        {"Test 8"},
        {"Test 9"},
        {"Test 10"}
    };
}

@Test(dataProvider = "parallelData")
public void testParallel(String data) {
    System.out.println(Thread.currentThread().getName() + " - " + data);
    // Tests run in parallel threads
}

}

Iterator DataProvider

import java.util.Iterator; import java.util.Arrays;

public class IteratorDataProviderTest {

@DataProvider(name = "iteratorData")
public Iterator<Object[]> provideIteratorData() {
    // Useful for large datasets - generates data on demand
    return Arrays.asList(
        new Object[]{"data1", 1},
        new Object[]{"data2", 2},
        new Object[]{"data3", 3}
    ).iterator();
}

@Test(dataProvider = "iteratorData")
public void testWithIterator(String name, int value) {
    assertNotNull(name);
    assertTrue(value > 0);
}

}

Lazy DataProvider for Large Datasets

import java.util.Iterator; import java.util.NoSuchElementException;

public class LazyDataProviderTest {

@DataProvider(name = "lazyData")
public Iterator<Object[]> provideLazyData() {
    return new Iterator<Object[]>() {
        private int current = 0;
        private final int max = 1000;

        @Override
        public boolean hasNext() {
            return current < max;
        }

        @Override
        public Object[] next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            // Generate data on demand
            return new Object[]{
                "User_" + current,
                "user" + current + "@example.com",
                current++
            };
        }
    };
}

@Test(dataProvider = "lazyData")
public void testLargeDataset(String name, String email, int id) {
    assertNotNull(name);
    assertTrue(email.contains("@"));
}

}

Factory Pattern

Basic Factory

import org.testng.annotations.*;

public class FactoryTest { private String browser;

@Factory
public static Object[] createInstances() {
    return new Object[] {
        new FactoryTest("chrome"),
        new FactoryTest("firefox"),
        new FactoryTest("safari")
    };
}

public FactoryTest(String browser) {
    this.browser = browser;
}

@Test
public void testHomePage() {
    System.out.println("Testing home page on: " + browser);
}

@Test
public void testLoginPage() {
    System.out.println("Testing login page on: " + browser);
}

}

Factory with DataProvider

public class FactoryWithDataProviderTest { private String username; private String role;

@Factory(dataProvider = "userRoles")
public FactoryWithDataProviderTest(String username, String role) {
    this.username = username;
    this.role = role;
}

@DataProvider(name = "userRoles")
public static Object[][] provideUserRoles() {
    return new Object[][] {
        {"admin", "ADMIN"},
        {"manager", "MANAGER"},
        {"user", "USER"},
        {"guest", "GUEST"}
    };
}

@Test
public void testUserPermissions() {
    System.out.println("Testing permissions for " + username + " with role " + role);
    // Test specific permissions based on role
}

@Test
public void testUserDashboard() {
    System.out.println("Testing dashboard for " + username + " with role " + role);
    // Test dashboard features based on role
}

@Override
public String toString() {
    return username + "_" + role;
}

}

External Data Sources

CSV DataProvider

import java.io.; import java.util.;

public class CsvDataProviderTest {

@DataProvider(name = "csvData")
public Object[][] provideCsvData() throws IOException {
    List<Object[]> data = new ArrayList<>();

    try (BufferedReader reader = new BufferedReader(
            new FileReader("src/test/resources/testdata.csv"))) {

        String line;
        // Skip header
        reader.readLine();

        while ((line = reader.readLine()) != null) {
            String[] values = line.split(",");
            data.add(new Object[]{
                values[0].trim(),  // username
                values[1].trim(),  // email
                Integer.parseInt(values[2].trim())  // age
            });
        }
    }

    return data.toArray(new Object[0][]);
}

@Test(dataProvider = "csvData")
public void testUserFromCsv(String username, String email, int age) {
    assertNotNull(username);
    assertTrue(email.contains("@"));
    assertTrue(age > 0);
}

}

JSON DataProvider

import com.fasterxml.jackson.databind.; import java.io.; import java.util.*;

public class JsonDataProviderTest {

@DataProvider(name = "jsonData")
public Object[][] provideJsonData() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<Map<String, Object>> testData = mapper.readValue(
        new File("src/test/resources/testdata.json"),
        new TypeReference<List<Map<String, Object>>>() {}
    );

    Object[][] data = new Object[testData.size()][3];
    for (int i = 0; i < testData.size(); i++) {
        Map<String, Object> entry = testData.get(i);
        data[i][0] = entry.get("name");
        data[i][1] = entry.get("email");
        data[i][2] = ((Number) entry.get("age")).intValue();
    }

    return data;
}

@Test(dataProvider = "jsonData")
public void testUserFromJson(String name, String email, int age) {
    assertNotNull(name);
    assertFalse(name.isEmpty());
}

}

Excel DataProvider

import org.apache.poi.ss.usermodel.; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.; import java.util.*;

public class ExcelDataProviderTest {

@DataProvider(name = "excelData")
public Object[][] provideExcelData() throws IOException {
    List<Object[]> data = new ArrayList<>();

    try (FileInputStream fis = new FileInputStream("src/test/resources/testdata.xlsx");
         Workbook workbook = new XSSFWorkbook(fis)) {

        Sheet sheet = workbook.getSheetAt(0);

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                data.add(new Object[]{
                    getCellValue(row.getCell(0)),
                    getCellValue(row.getCell(1)),
                    (int) row.getCell(2).getNumericCellValue()
                });
            }
        }
    }

    return data.toArray(new Object[0][]);
}

private String getCellValue(Cell cell) {
    if (cell == null) return "";
    return cell.getCellType() == CellType.STRING
        ? cell.getStringCellValue()
        : String.valueOf((int) cell.getNumericCellValue());
}

@Test(dataProvider = "excelData")
public void testUserFromExcel(String name, String email, int age) {
    assertNotNull(name);
    assertTrue(age >= 0);
}

}

Advanced Parameterization

Optional Parameters

public class OptionalParameterTest {

@Parameters({"browser", "timeout"})
@BeforeClass
public void setUp(
        String browser,
        @Optional("30000") String timeout) {

    System.out.println("Browser: " + browser);
    System.out.println("Timeout: " + timeout);
}

@Test
public void testMethod() {
    // Test implementation
}

}

Combining Parameters and DataProviders

public class CombinedParametersTest {

private String environment;

@Parameters("environment")
@BeforeClass
public void setUp(String environment) {
    this.environment = environment;
}

@DataProvider(name = "users")
public Object[][] provideUsers() {
    return new Object[][] {
        {"user1", "pass1"},
        {"user2", "pass2"}
    };
}

@Test(dataProvider = "users")
public void testLogin(String username, String password) {
    System.out.println("Testing on " + environment + " with user: " + username);
    // Combine XML parameter with DataProvider data
}

}

Dynamic DataProvider Based on Parameters

public class DynamicDataProviderTest {

private static String environment;

@Parameters("environment")
@BeforeClass
public static void setUp(@Optional("staging") String env) {
    environment = env;
}

@DataProvider(name = "environmentData")
public Object[][] provideEnvironmentData() {
    switch (environment) {
        case "production":
            return new Object[][] {
                {"prod-user1", "prod-api-key-1"},
                {"prod-user2", "prod-api-key-2"}
            };
        case "staging":
            return new Object[][] {
                {"staging-user1", "staging-api-key-1"},
                {"staging-user2", "staging-api-key-2"}
            };
        default:
            return new Object[][] {
                {"dev-user", "dev-api-key"}
            };
    }
}

@Test(dataProvider = "environmentData")
public void testApiAccess(String user, String apiKey) {
    System.out.println("Testing API access for: " + user + " on " + environment);
}

}

Data Provider Naming

Named Data Provider Rows

public class NamedDataProviderTest {

@DataProvider(name = "testCases")
public Object[][] provideTestCases() {
    return new Object[][] {
        // Each row can have a name for better reporting
        {"TC001_ValidLogin", "admin", "admin123", true},
        {"TC002_InvalidPassword", "admin", "wrong", false},
        {"TC003_EmptyUsername", "", "password", false},
        {"TC004_SpecialCharacters", "user@#$", "pass@#$", false}
    };
}

@Test(dataProvider = "testCases")
public void testLogin(String testCaseId, String username, String password, boolean expected) {
    System.out.println("Executing: " + testCaseId);
    // Test implementation
}

}

Best Practices

  • Keep DataProviders focused - One DataProvider per data type or scenario

  • Use external files for large datasets - CSV, JSON, or Excel for maintainability

  • Make DataProviders static when shared - Required for external DataProvider classes

  • Include test case identifiers - First column can be test case ID for tracing

  • Use meaningful DataProvider names - Clear names improve test reports

  • Consider parallel execution - Enable parallel flag for independent tests

  • Handle null values explicitly - Define behavior for null/empty data

  • Document expected formats - Comment data structure for complex providers

  • Use Iterator for large datasets - Avoid memory issues with lazy loading

  • Separate test data from test logic - Keep tests clean and data manageable

Common Pitfalls

  • Type mismatches - DataProvider types must match test method parameters

  • Missing static modifier - External DataProvider methods must be static

  • Array dimension errors - Must return Object[][] not Object[]

  • Null pointer exceptions - Not handling null values in data

  • Resource leaks - Not closing file streams in DataProviders

  • Tight coupling - Hard-coding environment-specific data

  • Over-parameterization - Too many parameters make tests hard to read

  • Missing test case IDs - Hard to trace failures without identifiers

  • Ignoring execution order - DataProvider rows may run in any order

  • Not considering parallelism - Shared state issues with parallel DataProviders

When to Use This Skill

  • Testing with multiple input combinations

  • Implementing boundary value testing

  • Creating cross-browser or cross-environment tests

  • Loading test data from external sources

  • Building parameterized test suites

  • Creating data-driven API tests

  • Implementing database-driven tests

  • Building reusable test data frameworks

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

android-jetpack-compose

No summary provided by upstream source.

Repository SourceNeeds Review
General

fastapi-async-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

storybook-story-writing

No summary provided by upstream source.

Repository SourceNeeds Review