TestNG – Parameter Test (XML and @DataProvider)
In this tutorial, we will show you how to pass parameters into a @Test
method, via XML @Parameters
or @DataProvider
.
1. Passing Parameters with XML
In this example, the properties filename is passing from testng.xml
, and inject into the method via @Parameters
.
package com.mkyong.testng.examples.parameter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class TestParameterXML {
Connection con;
@Test
@Parameters({ "dbconfig", "poolsize" })
public void createConnection(String dbconfig, int poolsize) {
System.out.println("dbconfig : " + dbconfig);
System.out.println("poolsize : " + poolsize);
Properties prop = new Properties();
InputStream input = null;
try {
//get properties file from project classpath
input = getClass().getClassLoader().getResourceAsStream(dbconfig);
prop.load(input);
String drivers = prop.getProperty("jdbc.driver");
String connectionURL = prop.getProperty("jdbc.url");
String username = prop.getProperty("jdbc.username");
String password = prop.getProperty("jdbc.password");
System.out.println("drivers : " + drivers);
System.out.println("connectionURL : " + connectionURL);
System.out.println("username : " + username);
System.out.println("password : " + password);
Class.forName(drivers);
con = DriverManager.getConnection(connectionURL, username, password);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mkyongserver
jdbc.username=mkyong
jdbc.password=password
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter">
<test name="example1">
<parameter name="dbconfig" value="db.properties" />
<parameter name="poolsize" value="10" />
<classes>
<class name="com.mkyong.testng.examples.parameter.TestParameterXML" />
</classes>
</test>
</suite>
Output
dbconfig : db.properties
poolsize : 10
drivers : com.mysql.jdbc.Driver
connectionURL : jdbc:mysql://localhost:3306/mkyongserver
username : mkyong
password : password
2. Passing Parameters with @DataProvider
2.1 Review a simple @DataProvider
example, passing a int
parameter.
package com.mkyong.testng.examples.parameter;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestParameterDataProvider {
@Test(dataProvider = "provideNumbers")
public void test(int number, int expected) {
Assert.assertEquals(number + 10, expected);
}
@DataProvider(name = "provideNumbers")
public Object[][] provideData() {
return new Object[][] {
{ 10, 20 },
{ 100, 110 },
{ 200, 210 }
};
}
}
Output
PASSED: test(10, 20)
PASSED: test(100, 110)
PASSED: test(200, 210)
2.2 The @DataProvider
is support passing an object
parameter. Below example shows you how to pass a Map
object as parameter.
package com.mkyong.testng.examples.parameter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestParameterDataProvider {
@Test(dataProvider = "dbconfig")
public void testConnection(Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("[Key] : " + entry.getKey()
+ " [Value] : " + entry.getValue());
}
}
@DataProvider(name = "dbconfig")
public Object[][] provideDbConfig() {
Map<String, String> map = readDbConfig();
return new Object[][] { { map } };
}
public Map<String, String> readDbConfig() {
Properties prop = new Properties();
InputStream input = null;
Map<String, String> map = new HashMap<String, String>();
try {
input = getClass().getClassLoader().getResourceAsStream("db.properties");
prop.load(input);
map.put("jdbc.driver", prop.getProperty("jdbc.driver"));
map.put("jdbc.url", prop.getProperty("jdbc.url"));
map.put("jdbc.username", prop.getProperty("jdbc.username"));
map.put("jdbc.password", prop.getProperty("jdbc.password"));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return map;
}
}
Output
[Key] : jdbc.url [Value] : jdbc:mysql://localhost:3306/mkyongserver
[Key] : jdbc.username [Value] : mkyong
[Key] : jdbc.driver [Value] : com.mysql.jdbc.Driver
[Key] : jdbc.password [Value] : password
PASSED: testConnection({jdbc.url=jdbc:mysql://localhost:3306/mkyongserver,
jdbc.username=mkyong, jdbc.driver=com.mysql.jdbc.Driver, jdbc.password=password})
3. @DataProvider + Method
This example shows you how to pass a different parameters depending on the test method name.
package com.mkyong.testng.examples.parameter;
import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestParameterDataProvider {
@Test(dataProvider = "dataProvider")
public void test1(int number, int expected) {
Assert.assertEquals(number, expected);
}
@Test(dataProvider = "dataProvider")
public void test2(String email, String expected) {
Assert.assertEquals(email, expected);
}
@DataProvider(name = "dataProvider")
public Object[][] provideData(Method method) {
Object[][] result = null;
if (method.getName().equals("test1")) {
result = new Object[][] {
{ 1, 1 }, { 200, 200 }
};
} else if (method.getName().equals("test2")) {
result = new Object[][] {
{ "[email protected]", "[email protected]" },
{ "[email protected]", "[email protected]" }
};
}
return result;
}
}
Output
PASSED: test1(1, 1)
PASSED: test1(200, 200)
PASSED: test2("[email protected]", "[email protected]")
PASSED: test2("[email protected]", "[email protected]")
4. @DataProvider + ITestContext
In TestNG, we can use org.testng.ITestContext
to determine what runtime parameters the current test method was invoked with. In this last example, we will show you how to pass parameters depending on the included group name.
package com.mkyong.testng.examples.parameter;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestParameterDataProvider {
@Test(dataProvider = "dataProvider", groups = {"groupA"})
public void test1(int number) {
Assert.assertEquals(number, 1);
}
@Test(dataProvider = "dataProvider", groups = "groupB")
public void test2(int number) {
Assert.assertEquals(number, 2);
}
@DataProvider(name = "dataProvider")
public Object[][] provideData(ITestContext context) {
Object[][] result = null;
//get test name
//System.out.println(context.getName());
for (String group : context.getIncludedGroups()) {
System.out.println("group : " + group);
if ("groupA".equals(group)) {
result = new Object[][] { { 1 } };
break;
}
}
if (result == null) {
result = new Object[][] { { 2 } };
}
return result;
}
}
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter">
<test name="example1">
<groups>
<run>
<include name="groupA" />
</run>
</groups>
<classes>
<class
name="com.mkyong.testng.examples.parameter.TestParameterDataProvider" />
</classes>
</test>
</suite>
Output
group : groupA
Done.
hi mkyoung,
this is article is awesome .And i need your inputs on running parallel testcases using paramters.
Thanks,
Saravanan Nallamuthu
can we call after test method when throw an exception in data provider iteration
Hi, just one thing: wouldn’t it be possible (and more manageable) to use 2 data providers for 2 methods? as in:
public class TestParameterDataProvider {
@Test(dataProvider = “numberProvider”)
public void test1(int number, int expectedNumber) {
Assert.assertEquals(number, expectedNumber);
}
@Test(dataProvider = “emailProvider”)
public void test2(String email, String expectedEmail) {
Assert.assertEquals(email, expectedEmail);
}
@DataProvider(name = “numberProvider”)
public Object[][] provideNumbers() {
return new Object[][] { { 1, 1 }, { 200, 200 } };
}
@DataProvider(name = “emailProvider”)
public Object[][] provideEmails() {
return new Object[][] {
{ “[email protected]”, “[email protected]” },
{ “[email protected]”, “[email protected]” }};
}
If I want to use the way of ITestContext, I have to config the tag of groups in the testng.xml?
I found that the ITestContext.getIncludeGroups() can not get the value of groups if there is no testng.xml.
For your example 2 the dataprovider takes its values from the java code itself.. Is there any possibility to load these values from the testng.xml
Hi ,
I am new to selenium. Is there any way if we can pass two Dataproviders in one function.
Please find below my code.
@DataProvider(parallel = true)
public static Iterator web_list (ITestContext context) throws IOException
{
List url = new ArrayList();
String webURL;
BufferedReader br = new BufferedReader(new FileReader(“WebList.txt”));
while( (webURL = br.readLine()) != null )
{
if( webURL.trim() != “”)
url.add(new Object[] {webURL});
}
return url.iterator();
}
@DataProvider(parallel = true)
public static Iterator browser_list (ITestContext context) throws IOException
{
List brw = new ArrayList();
String Browser;
BufferedReader br = new BufferedReader(new FileReader(“BrowserList.txt”));
while( (Browser = br.readLine()) != null )
{
if( Browser.trim() != “”)
brw.add(new Object[] {Browser});
}
return brw.iterator();
}
I want to pass above browser_list and web_list in one function.. I am trying like below..But I getting error in ‘@Test(dataProvider={ “web_list” , “browser_list” })’
@Test(dataProvider={ “web_list” , “browser_list” })
public void fun(String url, String browser) throws InterruptedException, MalformedURLException
{ }
Please help me how can I pass two different dataprovide values in one function.
Thanks in advance..
is there a way to print real arguments instead of : PASSED: parameterIntTest(TestNGTest6_3_0@dc6a77). For example desired output : PASSED: parameterIntTest(“Hello”,”123″)
Hi Mkyong,
Nice post I must say. There is one problem I am facing right now. It would be great if you can help me with that :
I am reading data from excel using data provider. Excel from which I am reading data is having some 25 odd columns and 250 odd rows. That means my test will be executed for 250 times with 25 arguments.. I am reading and returning Object[][] from data provider.
In turn I have declare so 25 arguments in my test method For example : @Test(groups = { “webservice” }, dataProvider = “testDP”)
public void testDP(String statusResponse,
String collateralized, String externalCIS, String fullName,
String hierarchy, String internalCIS, String limitAmount,
String limitCurrency, String limitId, String limitLevel,
String limitSource, String limitType, String locked,
String overrides, String parentCis, String parentFullName,
String parentLimitId, String parentPartyId, String partyId,
String displayString, String id, String name, String stream and so on……).
And the value of arguments are different for different test methods. All I want, is not to declare 25 arguments every time I am writing a test method, rather a approach similar to passing an object of class would be great. Some other solution will also work, if you can suggest…..
So example of what I want will be :
@Test(groups = { “webservice” }, dataProvider = “testDP”)
public void testDP(some_class obj)
{
//Then I can refer to variable values using obj
}
If I will take example of yours, then is there a way to do below :
@Test(dataProvider = “Data-Provider-Function”)
public void parameterIntTest(TestNGTest6_3_0 clzz) {
System.out.println(“Parameterized Number is : ” + clzz.getMsg());
System.out.println(“Parameterized Number is : ” + clzz.getNumber());
}
//This function will provide the patameter data
@DataProvider(name = “Data-Provider-Function”)
public Object[][] parameterIntTestProvider() {
TestNGTest6_3_0 obj = new TestNGTest6_3_0();
obj.setMsg(“Hello”);
obj.setMsg(“Hello123”); // Added
obj.setNumber(123);
obj.setNumber(456); // Added
return new Object[][]{
{obj}
};
}
I need to run test method 2 times as per my update and clzz object should be used to call getMsg and getNumber.
Thanks
MS
Im new to maven and testng
I got an issue: I cannot get parameter from suite xml file for my test when run Maven Test.
The result is this test is skipped:
——————————————————————————-
Test set: TestSuite
——————————————————————————-
Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.375 sec
I dont know why
Anything wrong here?
I appreciate so much
Thank you
This is my main test: hTest.java
====
package demo;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class hTest {
@Parameters({“user”})
@Test
public void getUser(String user)
{
System.out.println(“NAME= ” + user);
}
}
This is my suite hTest.xml
This is my pom.xml
4.0.0
test
sample
0.0.1-SNAPSHOT
BnS
test.suites
org.testng
testng
6.8.5
org.seleniumhq.selenium
selenium-java
2.33.0
org.seleniumhq.selenium
selenium-server
2.33.0
org.apache.maven.plugins
maven-surefire-report-plugin
2.14.1
${test.suite.dir}/hTest.xml
Hello MyKong
Do you have a tutorial for EVERYTHING???
Is there any short hand way (thru annotation) to pass parameter value directly without the testng.xml/DataProvider ?
Try using @Optional annotation.
Thanks for sharing! For the DataProvider, do you have to hardcode all data in the Java class? Won’t that violate the use of xml configuration file?
This one is Awesome !!Great help:)
I am using testng.xml to specify many different test parameters. For each test there is a name specified as part of the testng.xml format. How can I print out this name when the test method is running?