Right now, every test class has its own DataProvider methods. That means if the Banking login data is used by LoginTests, SecurityTests, and SmokeTests, you have three copies of the same DataProvider. The fix: create a centralized DataProviders class and reference it using dataProviderClass.
package com.practice.data;
import com.practice.utils.CsvUtils;
import com.practice.utils.ExcelUtils;
import org.testng.annotations.DataProvider;
import java.io.IOException;
/**
* Single source of truth for all test data.
* Every test class references this class using
* dataProviderClass = DataProviders.class
*/
public class DataProviders {
private static final String DATA_DIR =
"src/test/resources/test-data/";
// ===== Banking Portal Data =====
@DataProvider(name = "bankingLoginData")
public Object[][] bankingLoginData() throws IOException {
return ExcelUtils.readSheet(
DATA_DIR + "login-data.xlsx",
"BankingLogin");
}
@DataProvider(name = "bankingTransferData")
public Object[][] bankingTransferData()
throws IOException {
return ExcelUtils.readSheet(
DATA_DIR + "transfer-data.xlsx",
"Transfers");
}
// ===== Shopping Portal Data =====
@DataProvider(name = "shoppingSearchTerms")
public Object[][] shoppingSearchTerms()
throws IOException {
return CsvUtils.readCsv(
DATA_DIR + "search-terms.csv");
}
@DataProvider(name = "shoppingCheckoutData")
public Object[][] shoppingCheckoutData()
throws IOException {
return ExcelUtils.readSheet(
DATA_DIR + "checkout-data.xlsx",
"CheckoutScenarios");
}
// ===== PolicyDekho Data =====
@DataProvider(name = "insuranceQuoteData")
public Object[][] insuranceQuoteData()
throws IOException {
return ExcelUtils.readSheet(
DATA_DIR + "insurance-data.xlsx",
"QuoteScenarios");
}
@DataProvider(name = "insuranceClaimData")
public Object[][] insuranceClaimData()
throws IOException {
return CsvUtils.readCsv(
DATA_DIR + "claim-data.csv");
}
}import com.practice.data.DataProviders;
import org.testng.annotations.Test;
import org.testng.Assert;
public class BankingLoginTests extends BaseTest {
@Test(dataProvider = "bankingLoginData",
dataProviderClass = DataProviders.class)
public void testLogin(String username, String password,
String expectedResult,
String errorMessage) {
navigateTo("/banking");
LoginPage loginPage = new LoginPage(driver);
loginPage.loginAs(username, password);
if ("success".equals(expectedResult)) {
Assert.assertTrue(
new DashboardPage(driver).isLoaded());
} else {
Assert.assertTrue(
loginPage.isErrorDisplayed());
}
}
}
// Another test class reusing the same DataProvider
public class BankingSecurityTests extends BaseTest {
@Test(dataProvider = "bankingLoginData",
dataProviderClass = DataProviders.class)
public void testLoginSecurity(
String username, String password,
String expectedResult, String errorMessage) {
navigateTo("/banking");
LoginPage loginPage = new LoginPage(driver);
loginPage.loginAs(username, password);
// Security-specific assertions
if ("failure".equals(expectedResult)) {
Assert.assertFalse(
loginPage.getErrorMessage()
.contains("SQL"),
"Error message should not leak "
+ "technical details");
}
}
}Q: How do you share DataProviders across multiple test classes?
A: I create a centralized DataProviders class in the data or utils package. All @DataProvider methods live there. Test classes reference them using the dataProviderClass attribute: @Test(dataProvider = "loginData", dataProviderClass = DataProviders.class). This eliminates duplicate DataProvider code across test classes and makes data management centralized.
The DataProvider method must NOT be static. TestNG creates an instance of dataProviderClass and calls the method on that instance. If the method is static, TestNG will not find it and throws "DataProvider not found" error.
Organize your DataProviders class with clear section comments: // ===== Banking Portal Data =====. When the file grows to 20+ DataProviders, these sections save your sanity.
Key Point: Use dataProviderClass to share DataProviders across test classes. Keep all DataProviders in one centralized class.