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.
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!
Most helpful comment
Actually, parameters on method level exists. Here is an example: