DataProvider is TestNG's way of feeding data to test methods. It is a method that returns Object[][] — a two-dimensional array. Each inner array is one "order" for your test kitchen. TestNG runs your test method once for each inner array, passing the values as parameters.
The Object[][] structure looks like a table. Each row is a test case. Each column is a parameter. If you return 5 rows with 3 columns each, your test method will run 5 times, each time receiving 3 arguments.
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.Assert;
public class BankingLoginDDTest extends BaseTest {
@DataProvider(name = "loginCredentials")
public Object[][] loginData() {
return new Object[][] {
// username password expectedResult expectedMessage
{ "testuser", "password123", "success", "" },
{ "admin", "admin123", "success", "" },
{ "testuser", "wrongpass", "failure", "Invalid credentials" },
{ "nonexistent", "password123", "failure", "Invalid credentials" },
{ "", "password123", "failure", "Username is required" },
{ "testuser", "", "failure", "Password is required" },
{ "", "", "failure", "Username is required" },
{ "testuser'", "password123", "failure", "Invalid credentials" },
{ "test user", "password123", "failure", "Invalid credentials" },
};
}
@Test(dataProvider = "loginCredentials")
public void testBankingLogin(String username, String password,
String expectedResult,
String expectedMessage) {
navigateTo("/banking");
LoginPage loginPage = new LoginPage(driver);
loginPage.enterUsername(username);
loginPage.enterPassword(password);
loginPage.clickLogin();
if ("success".equals(expectedResult)) {
DashboardPage dashboard = new DashboardPage(driver);
Assert.assertTrue(dashboard.isLoaded(),
"Dashboard should load for user: " + username);
} else {
Assert.assertTrue(loginPage.isErrorDisplayed(),
"Error should appear for user: " + username);
if (!expectedMessage.isEmpty()) {
Assert.assertEquals(loginPage.getErrorMessage(),
expectedMessage,
"Error message mismatch for user: " + username);
}
}
}
}The name attribute in @DataProvider is required when the DataProvider method name is different from what you reference in @Test. If you skip the name, TestNG uses the method name itself. Best practice: always set a descriptive name.
// Option 1: Named DataProvider (recommended)
@DataProvider(name = "loginCredentials")
public Object[][] loginData() { ... }
@Test(dataProvider = "loginCredentials")
public void testLogin(...) { ... }
// Option 2: Method name IS the DataProvider name
@DataProvider
public Object[][] loginCredentials() { ... }
@Test(dataProvider = "loginCredentials")
public void testLogin(...) { ... }Q: What does a DataProvider return and how does TestNG use it?
A: A DataProvider returns Object[][] — a 2D array. Each inner array represents one set of test data. TestNG iterates over the outer array and calls the test method once for each inner array, passing the values as method parameters. For example, if the DataProvider returns 10 rows, the test runs 10 times. Each run is reported independently in the test report.
The number of elements in each inner array MUST match the number of parameters in your test method. If your DataProvider returns { "a", "b", "c" } but your test method only takes 2 parameters, TestNG throws an exception. 90% of freshers debug this for an hour before realizing the mismatch.
Add comments above your Object[][] rows to label what each column represents. When someone reads your code 6 months later, they should not have to count columns to figure out which value is which.
Key Point: DataProvider returns Object[][] — each row runs the test once. Always label your columns with comments.