@DataProvider and @Factory Annotation in TestNG

Pallavi Gaikwad
Posted on 27th Mar 2024 5:21 PM | 10 min Read | 60 min Implementation
#testng #dataprovider #factory

In this blog, we will be studying @DataProvider and @Factory annotations of TestNG.


As part of this study session, we will mainly discuss below annotations


@Test - Make a Class or Method as a part of the Test

@DataProvider -Marks a method as supplying data for a test method. The annotated method must return an Object[ ][ ], where each Object[ ] can be assigned the parameter list of the test method

@Factory - Marks a method as a factory that returns objects that will be used by TestNG as Test classes. The method must return Object[ ].



Let me start with one use case.


Let's understand UseCase


Suppose we are working in a project where we have multiple roles in multiple environments. every Role user has different access to screens and can perform various actions. as part of examples. suppose we have 5 different users with different access.

Users credentials are


  1. Username 1 / Password 1
  2. Username 2 / Password 2
  3. Username 3 / Password 3
  4. Username 4 / Password 4
  5. Username 5 / Password 5


Suppose we are testing a screen for all 5 users. so obviously we need to create 5 separate test-cases (for each user, 1 test case)

Now issue is, If in future we want to add more test users we always need to create new test cases.



so could you think about a solution?


The solution is @DataProvider in TestNG


What is @DataProvider Annotation?


@DataProvider is used to provide parameters to a test. If you provide the data provider to a test, the test will be run taking a different set of values each time. This is useful for a scenario like where you want to login to a site with a different set of username and password each time.

The test method will be executed using the same instance of the test class to which the test method belongs.


below is a simple data provider code


PlainBashC++C#CSSDiffHTML/XMLJavaJavascriptMarkdownPHPPythonRubySQL


@DataProvider(name = "test1-data")
public Object[][] data(){
Object[][] arr = newObject[5][2];
arr[0][0] = "Username 1"; arr[0][1] = "Password 1";
arr[1][0] = "Username 2"; arr[1][1] = "Password 2";
arr[2][0] = "Username 3"; arr[2][1] = "Password 3";
arr[3][0] = "Username 4"; arr[3][1] = "Password 4";
arr[4][0] = "Username 5"; arr[4][1] = "Password 5";
//the method returns the populated array containing test data.
return arr;
}


@DataProvider(name = "test1-data")

We are using @DataProvider annotation with data method. and we are giving name as test1-data. so that i can use this data-provider in multiple test-cases

public Object[][] data():

This method returns a two-dimensional array of objects (Object[][]). It's responsible for providing test data.

Object[][] arr = newObject[5][2];:

This line initializes a two-dimensional array named arr with dimensions 5x2. This means it has 5 rows and 2 columns.


How to use @DataProvider for @Test

@DataProvider that returns a two-dimensional array of objects. This method should provide the test data.

Syntax : @Test(dataProvider = "yourDataProviderName").

This tells TestNG to use the specified data provider method to provide test data for the test method.


For Example:


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

public class Test1 {

String env = "";

// DataProvider
@DataProvider(name = "test1-data")
public Object[][] data(){
Object[][] arr = new Object[5][2];
arr[0][0] = "Username 1"; arr[0][1] = "Password 1";
arr[1][0] = "Username 2"; arr[1][1] = "Password 2";
arr[2][0] = "Username 3"; arr[2][1] = "Password 3";
arr[3][0] = "Username 4"; arr[3][1] = "Password 4";
arr[4][0] = "Username 5"; arr[4][1] = "Password 5";
return arr;
}

//@BeforeMethod Annotation
@BeforeMethod
public void setup(){
System.out.println("Setup");
}

// Step 2: Use @Test with dataProvider attribute

@Test(dataProvider = "test1-data")
public void test1(String col1, String col2){
// Test method using data provided by DataProvider
System.out.println(env+" env url");
System.out.println("test1" + col1 + " - " + col2);
}

// Test method without DataProvider
@Test
void login(){
System.out.println(env + "env");
System.out.println("Login");
}
// AfterMethod
@AfterMethod
public void close(){
System.out.println("Close browser");
}


}

Output:



Git Repository: https://github.com/techellipticadigim/datahandle-testng-demo


Explanation of Code:


Import Statements

The Import Statements include necessary TestNG Annotations (@BeforMethod, @AfterMethod),@Test and @DataProvider for

defining the test methods ,setup , teardown & data provider.

@DataProvider(name = "test1-data")

This method provides test data for the test methods. It returns a 2D array of objects, where each row represents a set of test data.

@BeforeMethod

The setup() method annotated with @BeforeMethod is called before each test method execution. It's used to setup the test environment or perform any necessary preconditions for the test.

@Test(dataProvider = "test1-data")

The test1() method is annotated with @Test and uses the data provider test1-data to receive test data. It is executed for total Rows present in Object[][] array from data-provider method, each time with different sets of data from the data provider.

Test Method without @DataProvider (@Test)

The login() method is another test method annotated with @Test. Unlike test1(), it doesn't use a data provider. It will be executed once without any test data provided by a data provider.

@AfterMethod

The close() method annotated with @AfterMethod is called after each test method execution. It's used to clean up resources or perform any necessary postconditions after the test.




New Changes in Use Case...


Oops. Requirement got little changed. Now we have 3 new environments in the project. ie (dev, qa and uat) and management want us to run all our cases in all 3 environments at once.

environments are


  1. DEV environment
  2. QA environment
  3. UAT environments


now your all testcases (5 for @DataProvider one) should run 3 times for different environments


how will you resolve this issue ?


The solution is @Factory in TestNG


What is @Factory Annotations?


@Factory annotated method allows tests to be created at runtime depending on certain data sets or conditions. The method must return Object[].

A factory will execute all the test methods present inside a test class using separate instances of the class.

TestNG @Factory is used to create instances of test classes dynamically. This is useful if you want to run the test class any number of times.

For Example:


import org.testng.annotations.Factory;

public class AllCases{

@Factory
public Object[] allCases() {
Object[] env = newObject[3];
Test1 dev = new Test1();
dev.env = "dev";
Test1 qa = new Test1();
qa.env = "qa";
Test1 uat = new Test1();
uat.env = "uat";
env[0] = dev;
env[1] = qa;
env[2] = uat;
return env;
}
}

Output:


Git Repository: https://github.com/techellipticadigim/datahandle-testng-demo


Explanation of Code:


@Factory Annotation:

The "@Factory" annotation is used to generate test instances dynamically. In this case, it's applied to the allCases() method.

public Object[] allCases()

>This method is responsible for creating and returning an array of test instances.

>It initializes an array env to store the instances.

Test Instances Creation:

>Inside the method, three instances of the Test1 class are created, each representing a different testing environment (dev, qa, uat).

>For each instance, the "env" variable is set to indicate the environment.

Array Initialization:

>The created instances are stored in the "env" Variable.

>The array contains three elements, each representing a test instance with a different environment.

5.Return Statement:

>Finally, the method returns the env array containing the test instances.


How to use @factory Annotation?

Create a factory method inside your test class, annotated with @Factory.

This factory method should return an array of objects of the test class.

Each object in the array represents an instance of the test class with specific configurations or data.


Benefits of using @Factory:

  1. Configuration Flexibility: Allows running the same test cases with different configurations (e.g., different environments).
  2. Dynamic Test Generation: Enables generating test instances programmatically based on specific requirements.
  3. Code Reusability: Promotes reusability by creating a flexible testing framework that can adapt to different scenarios.


Note:

By using the @Factory annotation, you can efficiently manage test configurations and create a versatile testing framework that meets your project's requirements.









All Comments ()
Do You want to add Comment in this Blog? Please Login ?