What is the difference between DataProvider and Parameter in TestNG? DataProviders pass the different parameters on a single test in a single execution, whereas parameters pass the parameters just once per execution in TestNG.
There are two parameters supported by DataProvider are Method and ITestContext.
Note: TestNG comes up with DataProvider to automate the process of providing test-cases for execution. DataProvider helps with data-driven test cases that carry the same methods but can be run multiple times with different data sets. It also helps in providing complex parameters to the test methods.
Taken from the TestNG docs:
If you declare your @DataProvider as taking a java.lang.reflect.Method
as first parameter, TestNG will pass the current test method for this first parameter. This is particularly useful when several test methods use the same @DataProvider and you want it to return different values depending on which test method it is supplying data for.
For example, the following code prints the name of the test method inside its @DataProvider:
@DataProvider(name = "dp")
public Object[][] createData(Method m) {
System.out.println(m.getName()); // print test method name
return new Object[][] { new Object[] { "Cedric" }};
}
@Test(dataProvider = "dp")
public void test1(String s) {
}
@Test(dataProvider = "dp")
public void test2(String s) {
}
and will therefore display:
test1
test2
This can also be combined with the solution provided by desolat to determine data from the context and the method accordingly:
@DataProvider(name = "dp")
public Object[][] foodp(ITestContext ctx, Method method) {
// ...
}
You can access all defined parameters in your DataProvider using TestNG's dependency injection capabilies. This is some example DataProvider in need of the "test_param" parameter:
@DataProvider(name = "usesParameter")
public Object[][] provideTestParam(ITestContext context) {
String testParam = context.getCurrentXmlTest().getParameter("test_param");
return new Object[][] {{ testParam }};
}
This requires "test_param" to be defined in you suite.xml
:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite">
<parameter name="test_param" value="foo" />
<test name="tests">
<classes>
...
</classes>
</test>
</suite>
See the TestNG JavaDoc for details on the ITestContext class.
A more generic way of doing this would be to make use of the groups
annotation to build a custom list of values:
@DataProvider(name = "excelLoader")
public Object[][] createData(Method m) {
ArrayList<Object[]> excelFiles = new ArrayList<Object[]>;
// iterate over all the groups listed in the annotation
for (String excelFile : ((Test) m.getAnnotation(Test.class)).groups()) {
// add each to the list
excelFiles.add(new Object[] { excelFile });
}
// convert the list to an array
return excelFiles.toArray(new Object[excelFiles.size()]);
}
@Test(dataProvider = "excelLoader", groups = { "data1", "data2" })
public void test1(String excelFile) {
// we will test "data1.xls" and "data2.xls" in this test
String testExcelFile = excelFile + ".xls";
}
@Test(dataProvider = "excelLoader", groups = { "data2", "data3" })
public void test2(String excelFile) {
// we will test "data2.xls" and "data3.xls" in this test
String testExcelFile = excelFile + ".xls";
}
Alternatively you could also create your own annotation class that takes in custom elements so that you could do something more like:
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD, TYPE, CONSTRUCTOR})
public @interface FilesToTest {
public String[] value() default {};
}
@DataProvider(name = "excelLoader")
public Object[][] createData(Method m) {
ArrayList<Object[]> excelFiles = new ArrayList<Object[]>;
// iterate over all the groups listed in the annotation
for (String excelFile : ((FilesToTest) m.getAnnotation(FilesToTest.class)).value()) {
// add each to the list
excelFiles.add(new Object[] { excelFile });
}
// convert the list to an array
return excelFiles.toArray(new Object[excelFiles.size()]);
}
@Test(dataProvider = "excelLoader")
@FilesToTest({ "data1.xls", "data2.xls" })
public void myTest(String excelFile) {
// we will test "data1.xls" and "data2.xls" in this test
}
The answer from yshua is a bit limiting because you still have to hardcode the filepaths inside your data provider. This means you'd have to change the source code and then recompile to just rerun the test. This defeats the purpose of using XML files to configure the test run.
A better, definitely more hacky, kludge of a solution would be to create a dummy @test method that runs before suite, takes your filepaths as parameters and saves this information within the Class housing these test methods.
This solution isn't perfect, but until TestNG permits better parameter passing (Maybe this has changed) this might be viable for your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With