Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to pass parameters to TestNG DataProvider?

People also ask

What is the difference between DataProvider and parameter in TestNG?

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.

What kind of parameterization does DataProvider support?

There are two parameters supported by DataProvider are Method and ITestContext.

How does DataProvider work in TestNG?

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.