Testng: supporting parameters at method level?

Created on 12 Oct 2015  ·  12Comments  ·  Source: cbeust/testng

Is it possible to support special parameters at method level?
For instance,

<test name="Regression1">
<groups>
    <run>
      <exclude name="brokenTests"  />
      <include name="checkinTests"  />
    </run>
  </groups>

  <classes>
    <class name="test.IndividualMethodsTest">
      <methods>
        <include name="testMethod" param1="121" param2="1212"  />
      </methods>
    </class>
  </classes>
</test>

I am trying to achieve this by modifying testng code - I would appreciate any guidance/start for this.

Most helpful comment

Actually, parameters on method level exists. Here is an example:

<suite name="my-suite" verbose="1">
    <test name="my-test">
        <classes>
            <class name="testng.ex1.TestParams">
                <methods>
                    <include name="m1">
                        <parameter name="key1"  value="val1"/>
                        <parameter name="key2"  value="val2"/>
                    </include>
                    <include name="m2">
                        <parameter name="key1"  value="valA"/>
                        <parameter name="key2"  value="valB"/>
                    </include>
                </methods>
            </class>
        </classes>
    </test>
</suite>
package testng.ex1;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class TestParams {

    @Test
    @Parameters({ "key1", "key2" })
    public void m1(String key1, String key2) throws Exception {
        System.out.println(key1 + ", " + key2);
    }

    @Test
    @Parameters({ "key1", "key2" })
    public void m2(String key1, String key2) throws Exception {
        System.out.println(key1 + ", " + key2);
    }
}

All 12 comments

No, you should use a @DataProvider for this.

@cbeust, the challenge with @DataProvider is that it cannot be defined from testng.xml? The reason for passing this parameter, is that the data for method comes from a database and this parameter is the primary key. I want to use this key, fetch data, create a dataobject for the method at runtime using reflection. So, in short, even if I use a DataProvider, I have to pass a value at runtime to it, to indicate which set of rows it should pick from database. Please note, this is for a scenario with programmatic usage of testng.

You can define a limited amount of parameters in your testng.xml:

http://testng.org/doc/documentation-main.html#parameters-testng-xml

Cédric

On Mon, Oct 12, 2015 at 9:03 PM, JayVem [email protected] wrote:

@cbeust https://github.com/cbeust, the challenge with @DataProvider is
that it cannot be defined from testng.xml? The reason for passing this
parameter, is that the data for method comes from a database and this
parameter is the primary key. I want to use this key, fetch data, create a
dataobject for the method at runtime using reflection. So, in short, even
if I use a DataProvider, I have to pass a value at runtime to it, to
indicate which set of rows it should pick from database. Please note, this
is for a scenario with programmatic usage of testng.


Reply to this email directly or view it on GitHub
https://github.com/cbeust/testng/issues/823#issuecomment-147592710.

@cbeust Aren't these parameters at suite level? What if I wanted to create a complex data type at method level. For instance, consider this code...

public class EmployeeBenefitsCalculator {

    @Test
    public void calculateBenefits(Employee employee) {
        //do something with employee here.
    }
}

The Employee parameter that is being sent to calculateBenefits method has to be created from the database. How would I achieve this? I would like to pass a primary key and inside the calculateBenefits method, I want to read this primary key, fetch data from db and create an employee object for that test run. I know it sounds complicated. I think this is what I am looking for -

public class EmployeeBenefitsCalculator {

    @Test
    public void calculateBenefits(Employee employee) {
        employee = DataStore.fetch("id_from_testng_xml");
    }
}

How do I provide parameters to a dataprovider for a test at run time? How easy a change is it to create this behavior by altering testng source?

You can mix data provider + parameters. Your data provider will take primary key from the parameter and will create your Employee object + pass any other attributes. Then your test method will use the data provider and its attributes.
Easy! ;)

@juherr Could you give me an example of how I can I have multiple parameters at method level, each going to a dataprovider ?

@juherr To simplify my question, I am programmatically generating a testng.xml. Now, let's say I have a method modifyEmployee(Employee employee). I need to create an xml in such a way that this method is invoked 4 times, but each time with a different Employee. I would know the primary key of each of these employees at the time of creating testng.xml. So, what is the best way to achieve what I am trying to do?

I suppposed @DataProvider can work with @Parameters but I'm not sure (I should test it one day).
BTW, if I understand what you want, you can just try parameters on test level (parameters on method level don't exist):

<suite>
<test name="Regression1">
<parameter name="param1" value="121" />
<parameter name="param2" value="1212" />
<groups>
    <run>
      <exclude name="brokenTests"  />
      <include name="checkinTests"  />
    </run>
  </groups>

  <classes>
    <class name="test.IndividualMethodsTest">
      <methods>
        <include name="testMethod"  />
      </methods>
    </class>
  </classes>
</test>

<test name="Regression2">
<parameter name="param1" value="454" />
<parameter name="param2" value="4545" />
<groups>
    <run>
      <exclude name="brokenTests"  />
      <include name="checkinTests"  />
    </run>
  </groups>

  <classes>
    <class name="test.IndividualMethodsTest">
      <methods>
        <include name="testMethod"  />
      </methods>
    </class>
  </classes>
</test>
<suite>

You should ask your question on Staskoverflow or the mailing list if you want more ideas ;)

Actually, parameters on method level exists. Here is an example:

<suite name="my-suite" verbose="1">
    <test name="my-test">
        <classes>
            <class name="testng.ex1.TestParams">
                <methods>
                    <include name="m1">
                        <parameter name="key1"  value="val1"/>
                        <parameter name="key2"  value="val2"/>
                    </include>
                    <include name="m2">
                        <parameter name="key1"  value="valA"/>
                        <parameter name="key2"  value="valB"/>
                    </include>
                </methods>
            </class>
        </classes>
    </test>
</suite>
package testng.ex1;

import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class TestParams {

    @Test
    @Parameters({ "key1", "key2" })
    public void m1(String key1, String key2) throws Exception {
        System.out.println(key1 + ", " + key2);
    }

    @Test
    @Parameters({ "key1", "key2" })
    public void m2(String key1, String key2) throws Exception {
        System.out.println(key1 + ", " + key2);
    }
}

:+1: Good to know! I've never seen it before.

@JayVem I close the issue as it already exists.

another approach is to use a data-provider that fetches the keys from testng.xml. See example:

<suite name="my-suite" verbose="1">
    <test name="my-test">
        <classes>
            <parameter name="keys" value="key1,key2,key3,key4" />
            <class name="testng.ex2.TestParams" />
        </classes>
    </test>
</suite>
package testng.ex2;

import java.util.Arrays;
import java.util.List;

import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class TestParams {

    @Test(dataProvider = "dp")
    public void m1(Employee e) throws Exception {
        System.out.println("name: " + e.getName() + ", age: " + e.getAge());
    }

    @DataProvider(name = "dp")
    @Parameters("keys")
    public Object[][] createData(ITestContext ctx) {
        String keysString = ctx.getCurrentXmlTest().getLocalParameters().get("keys");
        List<String> keys = Arrays.asList(keysString.split(","));

        Object[][] result = new Object[keys.size()][1];
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            result[i] = new Object[] { new Employee(key) };
        }
        return result;
    }
}

package testng.ex2;

public class Employee {

    private final String name;
    private final int age;

    public Employee(String key) {
        // use 'key' to lookup employee in database
        name = key + "_name"; // dummy value
        age = 41; // dummy value
    }

    String getName() {
        return name;
    }

    int getAge() {
        return age;
    }
}

Thanks @drapostolos , I think dataprovider with testcontext sounds like it will do. I will try this out. Thank you so much for the quick answer!

Was this page helpful?
0 / 5 - 0 ratings