Dmitry Glushonkov
Dmitry Glushonkov

Reputation: 325

TestNG: Pass parameter to DataProvider from Maven

It seems I tried all the possible ways to achieve this, but no luck. I have a complex code in DataProvider (it really collects data in a complex way), which i want to be eventually parametrized by CI.

The first question here is how to even read parameters inside DataProvider.

1 One way is to get parameters from testng.xml this way:

    String lolo = context.getCurrentXmlTest().getParameter("testcases");

But this doesn't solve the problem, because .xml file must be static then, and I want to pass parameters to it from Maven.

2 The other way is to read parameters from @Factory in my case:

    String testCaseDataFilename = (method.getAnnotation(Factory.class)).parameters()[0];

Where @Factory is:

    @Factory(dataProvider="dataProviderMethod", parameters = {"authentication-testcases.json"})

It works too, but again, doesn't solve the problem, because now parameters must be harcoded in java test files, and my @Factory uses @DataProvider for itself, and it can't receive parameters from Maven implicitly.

Additionally, I have other test parameters, which are passed by Maven, but they are used only in @Test tests, not DataProvider, and @BeforeSuite successfully receives them.

I'll try to simplify:

I am calling maven

-Dtestname=signUp -Dmyparam=1 test

and I want my DataProvider to receive this value of Dmyparam and use it to gather data. All I achieved is receiving this data with @BeforeSuite and setting it globally, but the problem is DataProvider is called before the data is set.

Upvotes: 1

Views: 2027

Answers (2)

try-catch-finally
try-catch-finally

Reputation: 7634

All I achieved is receiving this data with @BeforeSuite and setting it globally, but the problem is DataProvider is called before the data is set.

I can't confirm this.

If you are able to declare the DataProvider within the test class you could have TestNG inject suite parameters into a @BeforeSuite method which then stores the values as instance fields:

public class Testcase3 {

    String foo;
    String bar;
    String baz;

    // Runs before the dataprovider
    @BeforeSuite
    // Injected from suite.xml and VM arguments
    @Parameters({"foo", "bar", "baz"})
    public void init(String foo, String bar, String baz) {
        this.foo = foo;
        this.bar = bar;
        this.baz = baz;
    }

    @DataProvider(name="foodp")
    public Object[][] foodp(){
        return new Object[][] {
            new String[] { "1: " + foo, "2: " + bar, "3: " + baz }
        };
    }

    // Injected from the data provider
    @Test(dataProvider="foodp")
    public void testFoo(String str1, String str2, String str3) {
        System.out.println("# test: str1=" + str1);
        System.out.println("# test: str2=" + str2);
        System.out.println("# test: str3=" + str3);
    }

}

With this suite.xml and the VM arguments -Dbaz=buzz

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="defaultsuite">
    <parameter name="foo" value="moo" />
    <parameter name="bar" value="far" />
    <test name="alltests">
        <classes>
            <class name="testng.tests.Testcase3"></class>
        </classes>
    </test>
</suite>

It prints:

# test: str1=1: moo
# test: str2=2: far
# test: str3=3: buzz

You can also have TestNG inject parameters into a factory:

public class TestFactory {

    @Factory
    @Parameters({"foo", "bar", "baz"})
    public Object[] createTestInstances(String foo, String bar, String baz) {
        Object[] testcases = new Object[1];

        testcases[0] = new Testcase4();
        ((Testcase4) testcases[0]).initDataProvider(foo, bar, baz);

        return testcases;
    }

}

Your test could receive the data this way:

public class Testcase4 {

    String foo;
    String bar;
    String baz;

    public void initDataProvider(String foo, String bar, String baz) {
        this.foo = foo;
        this.bar = bar;
        this.baz = baz;
    }

    // ...
}

This works since at least TestNG 6.9.10 and newer.

Upvotes: 0

juherr
juherr

Reputation: 5740

-D is setting a system property.

You'll be able to get it in your code with System.getProperty("MyParam").

Upvotes: 2

Related Questions