Using TestNG @Factory Annotation with @Dataprovider

Abhishek Dhoundiyal
3 min readFeb 26, 2023

TestNG @Factory annotation is used to specify a method as a factory for providing objects to be used by TestNG for test classes.

The method marked with @Factory annotation and must return Object[].

First, let’s understand the difference between @factory and @DataProvider annotation?

TestNG @Factory annotation is used to create instances of test classes dynamically. This is useful if you want to run the test class for “N” of times.

The objects returned can be of any class (not necessarily the same class as the factory class).

Whereas, @Dataprovider is used to provide parameters to a test. In simple words DataProviders pass data to @Test annotated methods in TestNG and so the same test method can be run multiple times with the different data-sets.

Now first, let’s understand the use case:

Use case: Factories allow us to create tests dynamically. For example, imagine you want to create a test method that will access a page on a Web site several times, and you want to invoke it with different values. In simple words if we want to run the test class for “N” of times.

Now let’s understand, how we can use @Factory with @DataProvider?

@Factory can be used with data providers, and we can use this functionality by declaring the @Factoryannotation either on a regular method or on a constructor (As shown below).

Here is an example:

Factory Class:

Key notes:

  • Here we have used the @DataProvider feature with the @Factory annotation for creating tests at runtime.
  • In the below case we have only defined the Object[] tests = new Object[1] one time because we are using the @DataProvider to pass data dynamically to the @Factorymethod.

TestNGFactory.class

public class TestNGFactory {

@Factory(dataProvider ="GetItem")
public Object[] getTestClasses(String param, String url) {
Object[] tests = new Object[1];
tests[0] = new Test1(url, param);

return tests;
}


@DataProvider(name = "GetItem")
public Object[][] getItem() {
Object list[][] = new Object[3][2];
list[0][0] = "Param 1";
list[0][1] = "URL 1";

list[1][0] = "Param 2";
list[1][1] = "URL 2";

list[2][0] = "Param 3";
list[2][1] = "URL 3";

return list;

}

}

Note: Without @DataProvider, we just have to create the Test1 class object multiple times and with hardcoded data (as shown below).

@Factory
public Object[] getTestClassesWithout() {
Object[] tests = new Object[3];
tests[0] = new Test1("URL 1", "Param 1");
tests[1] = new Test1("URL 2", "Param 2");
tests[2] = new Test1("URL 3", "Param 3");
return tests;
}

Test Class: Which need to executed multiple times with different set of test data.

Key notes:

  • Here, we have to declared a parameterized constructor, which accepts a specific parameters url and param. So that we can easily initialize the data members of a class with distinct values (As shown below) and can execute our test with different set of test data.

Test1.class

import org.testng.annotations.Test;

public class Test1 {

String url = "";
String param = "";

public Test1(String url, String param){
this.url = url;
this.param = param;
}

@Test
public void testData(){
System.out.println("Param = "+param+", url = "+url);
}
}

Now, execute the TestNGFactory.class and this will yield the below result:

--

--