TestNG @DataProvider Example

In this post we will learn about TestNG @DataProvider annotation to parameterize your tests in order to write data-driven tests. In data-driven testing, we run the same tests multiple times but with different sets of data which we pass into test methods using parameters.Let’s get going.


Let’s take a simple Calculator example:

package com.websystique.testng;

public class Calculator {

	public int add(int a, int b){
		return a+b;
	}

}

Above class have only one method. In traditional @Test, in order to test add method, we would be hard-coding a certain value for a, b and expected outcome right into @Test.

But what if we want to test this add method against several different values for a, b and expected outcome. Code duplication of test method is not a good option. In these kind of situations, we can use @DataProvider annotation.

Below is a trivial test class to test add method:

package com.websystique.testng;

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

public class TestNGDataProviderExample {

	@DataProvider(name = "addMethodDataProvider")
	public Object[][] dataProvider() {
		return new Object[][] { { 2, 5, 7 }, { 3, 7, 10 }, { 4, 5, 9 } };
	}

	@Test(dataProvider = "addMethodDataProvider")
	public void testAddMethod(int a, int b, int result) {
		Calculator calculator = new Calculator();
		Assert.assertEquals(calculator.add(a, b), result);
	}

}

A method annotated with @DataProvider acts as data-provider for other tests. The annotated method must return an Object[][] where each Object[] can be assigned the parameter list of the test method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation.

In above example, we have created a data-provider method using @DataProvider annotation and assigned a name to it. This data-provider method, returns different sets of parameters (a,b,sum). Then in our test testAddMethod, we refer to the same data-provider using it’s name. With this way, the @Test method testAddMethod will be called 3 times, as there are 3 sets of parameter in Object[][] of data-provider method. Each item in object[][], maps uniquely to parameters a,b & expected outcome in testAddMethod.

Run above test. Following is the output.

PASSED: testAddMethod(2, 5, 7)
PASSED: testAddMethod(3, 7, 10)
PASSED: testAddMethod(4, 5, 9)

===============================================
    Default test
    Tests run: 3, Failures: 0, Skips: 0
===============================================

You can see that @Test testAddMethod was executed 3 times as there were 3 sets of parameter provided by @DataProvider.

Multiple DataProviders Example

Let’s suppose we have multiple methods to test this time. It means we will need multiple data-providers, one for each test method.

package com.websystique.testng;

public class Calculator {

	public int add(int a, int b){
		return a+b;
	}

	public int subtract(int a, int b){
		return a-b;
	}
	
	public int multiply(int a, int b){
		return a * b;
	}

}

Let’s also refactor the @DataProvider in a separate class to make it more manageable.

Below is an independent class with all @DataProvider’s in one place. This way our actual Test class will not be polluted.

package com.websystique.testng;

import org.testng.annotations.DataProvider;

public class CalculatorDataProvider {

	@DataProvider(name = "addMethodDataProvider")
	public static Object[][] addMethodDataProvider() {
		return new Object[][] { { 2, 5, 7 }, { 3, 7, 10 }, { 4, 5, 9 } };
	}

	@DataProvider(name = "subtractMethodDataProvider")
	public static Object[][] subtractMethodDataProvider() {
		return new Object[][] { { 2, 5, -3 }, { 3, 7, -4 }, { 24, 5, 19 } };
	}

	@DataProvider(name = "multiplyMethodDataProvider")
	public static Object[][] multiplyMethodDataProvider() {
		return new Object[][] { { 2, 5, 10 }, { 3, 7, 21 }, { 4, 5, 20 } };
	}

}

Now let’s write the test class to test all 3 methods of Calculator class.

package com.websystique.testng;

import org.testng.Assert;
import org.testng.annotations.Test;

public class TestNGMultipleDataProviderExample {

	@Test(dataProvider = "addMethodDataProvider", dataProviderClass = CalculatorDataProvider.class)
	public void testAddMethod(int a, int b, int expectedResult) {
		Calculator calculator = new Calculator();
		Assert.assertEquals(calculator.add(a, b), expectedResult);
	}

	@Test(dataProvider = "subtractMethodDataProvider", dataProviderClass = CalculatorDataProvider.class)
	public void testSubtractMethod(int a, int b, int expectedResult) {
		Calculator calculator = new Calculator();
		Assert.assertEquals(calculator.subtract(a, b), expectedResult);
	}

	@Test(dataProvider = "multiplyMethodDataProvider", dataProviderClass = CalculatorDataProvider.class)
	public void testMultiplyMethod(int a, int b, int expectedResult) {
		Calculator calculator = new Calculator();
		Assert.assertEquals(calculator.multiply(a, b), expectedResult);
	}

}

Notice a new dataProviderClass attribute within @Test annotation. This attribute allows you to specify the data-provider class which will contain the data-provider this @Test method will be using. Code is cleaner this time, and all methods got there own data-providers.

Execute above Tests. Following is the outcome:


PASSED: testAddMethod(2, 5, 7)
PASSED: testAddMethod(3, 7, 10)
PASSED: testAddMethod(4, 5, 9)
PASSED: testMultiplyMethod(2, 5, 10)
PASSED: testMultiplyMethod(3, 7, 21)
PASSED: testMultiplyMethod(4, 5, 20)
PASSED: testSubtractMethod(2, 5, -3)
PASSED: testSubtractMethod(3, 7, -4)
PASSED: testSubtractMethod(24, 5, 19)

===============================================
    Default test
    Tests run: 9, Failures: 0, Skips: 0
===============================================

It’s evident that all three @Test methods took data from there respective dataProviders, independent of others.

That’s it.

References