TestNG

TestNG DataProvider Example

In this article, I am going to show you some examples of DataProvider.

It is one of the methods used in TestNG to support data-driven testing.

Before I proceed with my examples, I will brief you on data-driven testing but first let’s get started with the setup details:

  • I am using Eclipse as the IDE, version Luna 4.4.1.
  • I will be running the tests using eclipse TestNG plugin so you need to install TestNG Eclipse Plugin.

1. What is data-driven testing?

There are times when we would like to run our tests against different data sets. Instead of hard coding the data set within tests itself, it will be more appropriate if we could pass our data as parameters to the test method. Thus the test logic remains same but the data on which the test is run changes and this is called data-driven testing.

One of the most important features of TestNG is its data-driven testing. It allows the user to pass parameter values to the test method as arguments, so the test ends up running for each data-set passed in.

TestNG supports two different ways of injecting parameter values.

  1. Parameterization through testng.xml
  2. DataProvider

In order to know when we should use DataProvider, we also need to know a bit about the other method where we inject parameter values through testng.xml.

There is also the factory way where we create multiple instances of the test class with different constructor data.

2. Parameter Example

Parameterization through testng.xml is one of the methods of injecting parameter values. This method is useful if the data set is limited to just a few rows and the values are of simple types like String, int etc. The parameters are declared in testng.xml, where the name attribute defines name of the parameter and value attribute defines the parameter value.

paramTestng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="ParameterExampleSuite" parallel="false">
  <test name="ParameterTest">
    <classes>
      <parameter name="param1" value="2"></parameter>
      <parameter name="param2" value="and a string parameter"></parameter>
      <class name="com.javacodegeeks.testng.ParameterExample"/>
    </classes>
  </test>
</suite>

You will have to use @Parameters annotation to pass the parameter values. The parameter name has to be same as the one declared in testng.xml.

ParameterExample:

package com.javacodegeeks.testng;

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

public class ParameterExample {
	@Parameters({"param1", "param2"})
	@Test	
	public void paramTest(int p1, String p2) {
		System.out.println("Parameter Example: Data(" + p1 + ", " + p2 + ")");
	}
}

Output:

[TestNG] Running:
  C:\javacodegeeks_ws\testNgDataProvider\test\com\javacodegeeks\testng\parmTestng.xml

Parameter Example: Data(2, and a string parameter)

===============================================
ParameterExampleSuite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

3. Example of DataProvider

If you want to provide the test data, the DataProvider way, then we need to declare a method that returns the data set in the form of two dimensional object array Object[][]. The first array represents a data set whereas the second array contains the parameter values.

The DataProvider method can be in the same test class or one of its super classes. It is also possible to provide DataProvider in another class but then the method has to be static. I will go into the details in my next example on static DataProvider.

Once we have added the method we need to annotate it using @DataProvider to let TestNG know that it is a DataProvider method. You can also provide a name to it using the name attribute of the DataProvider annotation but this is optional. If one hasn’t provided the name, name of the method will be used to refer to it.

If a test wants to use the DataProvider, it can do so by specifying the name of the DataProvider in dataProvider attribute of @Test annotation.

Define the test class in testng.xml.

testng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="DataProviderExampleSuite" parallel="false">
  <test name="InstanceDataProviderTest">
    <classes>
      <class name="com.javacodegeeks.testng.InstanceDataProviderExample"/>
    </classes>
  </test>
</suite>

We have provided the DataProvider method getData within the test class itself. Note that it is annotated with @DataProvider. Since it doesn’t have the name attribute, its name by default will be getData. It returns two sets of data, each set of which contains two values, an integer and a string value.

We want the test method instanceDbProvider to run for each set of data that DataProvider method getData returns. In order for the test method instanceDbProvider to use the DataProvider, we need to specify the DataProvider name in the dataProvider attribute of @Test annotation.

InstanceDataProviderExample:

package com.javacodegeeks.testng;

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

public class InstanceDataProviderExample {
	@Test(dataProvider="getData")
	public void instanceDbProvider(int p1, String p2) {
		System.out.println("Instance DataProvider Example: Data(" + p1 + ", " + p2 + ")");
	}	
	
	@DataProvider
	public Object[][] getData() {
		return new Object[][]{{5, "five"}, {6, "six"}};
	}
}

Output:

[TestNG] Running:
  C:\javacodegeeks_ws\testNgDataProvider\test\com\javacodegeeks\testng\testng.xml

Instance DataProvider Example: Data(5, five)
Instance DataProvider Example: Data(6, six)

===============================================
DataProviderExampleSuite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

4. Example of static DataProvider

DataProvider method can also be defined in a separate class as a static method, in which case, the test method using it has to specify both the DataProvider name and its class in the @Test attributes dataProvider and dataProviderClass.

staticDataProviderTestng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="StaticDataProviderExampleSuite" parallel="false">
  <test name="StaticDataProviderTest">
    <classes>
      <class name="com.javacodegeeks.testng.StaticDataProviderExample"/>
    </classes>
  </test>
</suite>

StaticDataProviderExample:

package com.javacodegeeks.testng;

import org.testng.annotations.Test;

public class StaticDataProviderExample {	
	
	@Test(dataProvider="client1", dataProviderClass=DataProviderSource.class)
	public void client1Test(Integer p) {
		System.out.println("Client1 testing: Data(" + p + ")");
	}	
	
	@Test(dataProvider="client2", dataProviderClass=DataProviderSource.class)
	public void client2Test(Integer p) {
		System.out.println("Client2 testing: Data(" + p + ")");
	}		
}

Output:

[TestNG] Running:
  C:\javacodegeeks_ws\testNgDataProvider\test\com\javacodegeeks\testng\staticDataProviderTestng.xml

Client1 testing: Data(1)
Client2 testing: Data(2)

===============================================
StaticDataProviderExampleSuite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

5. Example of DataProviders with Method and ITestContext parameters

Till now we have seen DataProvider methods without any parameters. Now I am going to show you other variations of DataProvider methods which can receive two types of parameters Method and ITestContext. This is useful if you want to use the same DataProvider but want different data sets returned, based on the test method being invoked or the test suite/test type it belongs to.

You can specify just the Method parameter or ITestContext parameter or both the parameters. Based on the parameters used, TestNg will set the parameter values before invoking the DataProvider method.

In this example, I have three types of tests:

  1. UnitLevel
  2. AcceptanceLevel
  3. IntegrationLevel

In case of UnitLevel testing, the DataProvider returns different data sets based on the test method being invoked.
In case of AcceptanceLevel and IntegrationLevel testing, the DataProvider returns different data sets based on the test type.

We define the test types and their classes in paramDataProviderTestng.xml.

paramDataProviderTestng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="DataProviderParameterExampleSuite" parallel="false">
  <test name="UnitLevel">
    <classes>
      <class name="com.javacodegeeks.testng.DataProviderParametersExample"/>
    </classes>
  </test>
  
  <test name="AcceptanceLevel">
    <classes>
      <class name="com.javacodegeeks.testng.DataProviderParametersAcceptanceExample"/>
    </classes>
  </test>
  
  <test name="IntegrationLevel">
    <classes>
      <class name="com.javacodegeeks.testng.DataProviderParametersIntegrationExample"/>
    </classes>
  </test>
</suite>

Class DataProviderParametersExample contains test methods for UnitLevel testing. For each test method, the DataProvider should be able to provide different data sets.

DataProviderParametersExample:

package com.javacodegeeks.testng;

import org.testng.annotations.Test;

public class DataProviderParametersExample {	
	
	@Test(dataProvider="scenarioData", dataProviderClass=DataProviderSource.class)
	public void scenario1(String scenarioData) {
		System.out.println("Scenario testing: Data(" + scenarioData + ")");
	}
	
	@Test(dataProvider="scenarioData", dataProviderClass=DataProviderSource.class)
	public void scenario2(String scenarioData) {
		System.out.println("Scenario testing: Data(" + scenarioData + ")");
	}
	
	@Test(dataProvider="scenarioData", dataProviderClass=DataProviderSource.class)
	public void commonScenarios(String scenarioData) {
		System.out.println("Common Scenarios testing: Data(" + scenarioData + ")");
	}
}

Class DataProviderParametersAcceptanceExample has just one test method for AcceptanceLevel testing.

DataProviderParametersAcceptanceExample:

package com.javacodegeeks.testng;

import org.testng.annotations.Test;

public class DataProviderParametersAcceptanceExample {	
	
	@Test(dataProvider="TestType", dataProviderClass=DataProviderSource.class)
	public void acceptanceTest(String data) {
		System.out.println("Acceptance testing: Data(" + data + ")");
	}
}

Class DataProviderParametersIntegrationExample contains method for IntegrationLevel testing. If you notice, it uses the same dataProvider as the one used by AcceptanceLevel test.

DataProviderParametersIntegrationExample:

package com.javacodegeeks.testng;

import org.testng.annotations.Test;

public class DataProviderParametersIntegrationExample {	

	@Test(dataProvider="TestType", dataProviderClass=DataProviderSource.class)
	public void integrationTest(String data) {
		System.out.println("Integration testing: Data(" + data + ")");
	}
}

The DataProviderSource contains all the DataProvider methods required for UnitLevel, AcceptanceLevel and IntegrationLevel. Method getScenarioData returns different data sets for each UnitLevel test methods. Likewise, method getTestTypeData returns different data sets based on the test type AcceptanceLevel or IntegrationLevel.

DataProviderSource:

package com.javacodegeeks.testng;

import java.lang.reflect.Method;

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

public class DataProviderSource {

	@DataProvider(name="client1")
	public static Object[][] getClient1Data() {
		return new Object[][]{{1}};		
	}
	
	@DataProvider(name="client2")
	public static Object[][] getClient2Data() {
		return new Object[][]{{2}};		
	}
	
	@DataProvider(name="scenarioData")
	public static Object[][] getScenarioData(Method method) {		
		String testCase = method.getName();
		if ("scenario1".equals(testCase)) {
			return new Object[][]{{"Scenario1 data"}};
		} else if ("scenario2".equals(testCase)) {
			return new Object[][]{{"Scenario2 data"}};
		} else {
			return new Object[][]{{"Common scenario data"}};
		}
	}	
	
	@DataProvider(name="TestType")
	public static Object[][] getTestTypeData(ITestContext context) {		
		String testName = context.getName();
		if ("IntegrationLevel".equals(testName)) {
			return new Object[][]{{"Integration test data"}};
		} else if ("AcceptanceLevel".equals(testName)) {
			return new Object[][]{{"Acceptance test data"}};
		} else {
			return new Object[][]{{"Common test data"}};
		}
	}	
}

Output:

[TestNG] Running:
  C:\javacodegeeks_ws\testNgDataProvider\test\com\javacodegeeks\testng\paramDataProviderTestng.xml

Common Scenarios testing: Data(Common scenario data)
Scenario testing: Data(Scenario1 data)
Scenario testing: Data(Scenario2 data)
Acceptance testing: Data(Acceptance test data)
Integration testing: Data(Integration test data)

===============================================
DataProviderParameterExampleSuite
Total tests run: 5, Failures: 0, Skips: 0
===============================================

6. Example of DataProvider returning strong typed Objects

In this example, DataProvider returns a strong typed java object like Employee objects instead of primitive types like String.

Define the test class in empTestng.xml.

empTestng.xml:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="DataProviderParameterEmpSuite" parallel="false">
  <test name="EmpTest">
    <classes>
      <class name="com.javacodegeeks.testng.DataProviderParametersEmployeeExample"/>
    </classes>
  </test>  
</suite>

The Employee bean that our DataProvider will return.

Employee:

package com.javacodegeeks.testng;

public class Employee {
	private String name;

	public Employee(String name) {
		this.name = name;
	}

	public String toString() {
		return "Employee: " + name;
	}
}

In the below test class, DataProvider method getEmployeeData returns an array of Employee objects.

DataProviderParametersEmployeeExample:

package com.javacodegeeks.testng;

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

public class DataProviderParametersEmployeeExample {	
	
	@Test(dataProvider="employeeData")
	public void empTest(Employee employee) {
		System.out.println("Employee testing: Data(" + employee + ")");
	}	
	
	
	@DataProvider(name="employeeData") 
	public Object[][] getEmployeeData() {
		return new Object[][]{{new Employee("Joe")}, {new Employee("Sam")}};
	}
}

Output:

[TestNG] Running:
  C:\javacodegeeks_ws\testNgDataProvider\test\com\javacodegeeks\testng\empTestng.xml

Employee testing: Data(Employee: Joe)
Employee testing: Data(Employee: Sam)

===============================================
DataProviderParameterEmpSuite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

Download the Eclipse Project

In this article I have shown you several examples of TestNG DataProvider.

Download
You can download the full source code of this example here: testNgDataProvider.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button