How To Use Singleton Class to Manage Instance Variables in Automation Framework – Java

Introduction

In the previous post, we have seen how maximum beginners and experienced Selenium professionals apply inheritance with TestNG annotations while setup test scripts and end up with encountering NullPointerException. We have solved NullPointerException by converting instance variables to Static variables.

We can solve the above problem using a Singleton design pattern as well. Let’s learn about it.

Dependency version details

TestNG version used as below:-



    org.testng
    testng
    7.1.0
    test

Singleton Class

Let’s think of a scenario. A money bank may have many branches and many registered customers can withdraw or deposit or access there account at any time any place. Bank has a centralized common server where details of each customer are stored. If a new branch is opened it will also access data from the same server. If a brach is closed then also server will have customer’s data. In short, there is a common place where the state of data is stored.

We can consider an example of money withdrawal from ATM. If a customer tries to withdraw money simultaneously from two places, surely it will fail in one place because they also have a common place where data is kept updated. We can call that common place as a Singleton class.

When we develop a class in such a way that it can have the only instance at any time, is called a Singleton class. If a class is not instantiated then instantiate it and if the class is already instantiated return the same instantiated instance of the class. If we allow only one instance of any class that means we will have a shared object (somewhat how does a class variable or static variable works). This will solve our problem explained in the previous post. Variables initialized in TestNG annotated method will be stored in a common object for usage wherever we want.

Singleton class to store shared variables

package SecondTestNullPointerExceptionWithSingleton;

public class SharedVariables {

	// Private instance of class
	private static final SharedVariables instance = new SharedVariables();

	// Private constructor to control object creation of class
	private SharedVariables() {
	}

	// Return unidealized instance of class 
	public static SharedVariables getInstance() {
		return instance;
	}

	// A private variable with getter and setter methods
	private String someVariable;

	public String getSomeVariable() {
		return someVariable;
	}

	public void setSomeVariable(String someVariable) {
		this.someVariable = someVariable;
	}
}

Setup class with TestNG annotation

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.BeforeSuite;

public class Setup {

	// Get same instance of SharedVariables always
	SharedVariables sharedVariables = SharedVariables.getInstance();

	@BeforeSuite
	public void setupVariable() {
		System.out.println("Executing setupVariable...");
		sharedVariables.setSomeVariable("someValue");
	}

}

FirstTestNG class

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.Test;

public class FirstTestNGClass extends Setup{
	
	@Test
	public void firstMethodOfFirstTestNGClass()
	{
		System.out.println("Executing firstMethodOfFirstTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
	}
	
	@Test
	public void secondMethodOfFirstTestNGClass()
	{
		System.out.println("Executing secondMethodOfFirstTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
	}
}

SecondTestNG class

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.Test;

public class SecondTestNGClass extends Setup{
	
	@Test
	public void firstMethodOfSecondTestNGClass()
	{
		System.out.println("Executing firstMethodOfSecondTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
	}
	
	@Test
	public void secondMethodOfSecondTestNGClass()
	{
		System.out.println("Executing secondMethodOfSecondTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
	}
}

SecondTestNullPointerExceptionWithSingleton.xml




  
    
      
      
    
   
 

Output
[RemoteTestNG] detected TestNG version 7.0.1
Executing setupVariable...
Executing firstMethodOfFirstTestNGClass...
Value of someVariable is : someValue
Executing secondMethodOfFirstTestNGClass...
Value of someVariable is : someValue
Executing firstMethodOfSecondTestNGClass...
Value of someVariable is : someValue
Executing secondMethodOfSecondTestNGClass...
Value of someVariable is : someValue

===============================================
Suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================

You may ask in the above Singleton class creating variables in advance will be difficult and how can we save random variables. We can make out singleton class more advance with Map where will give user flexibility to save any data. This implementation even helps in sharing context among tests.

Singleton class with Map

package SecondTestNullPointerExceptionWithSingleton;

import java.util.HashMap;

public class SharedVariablesMap {

	// Private instance of class
	private static final SharedVariablesMap instance = new SharedVariablesMap();
	
	private static HashMap dataStore = new HashMap<>();

	// Private constructor to control object creation of class
	private SharedVariablesMap() {
	}

	// Return unidealized instance of class 
	public static SharedVariablesMap getInstance() {
		return instance;
	}
	
	public void store(String key, String value)
	{
		dataStore.put(key, value);
	}
	
	public Object get(String key)
	{
		return dataStore.get(key);
	}
}

Setup class

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.BeforeSuite;

public class Setup {

	// Get same instance of SharedVariables always
	SharedVariables sharedVariables = SharedVariables.getInstance();
	SharedVariablesMap sharedVariablesMap = SharedVariablesMap.getInstance();

	@BeforeSuite
	public void setupVariable() {
		System.out.println("Executing setupVariable...");
		sharedVariables.setSomeVariable("someValue");
		sharedVariablesMap.store("Name", "Amod");
	}

}

FirstTestNG class

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.Test;

public class FirstTestNGClass extends Setup{
	
	@Test
	public void firstMethodOfFirstTestNGClass()
	{
		System.out.println("Executing firstMethodOfFirstTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
		System.out.println("Value of name is :"+ sharedVariablesMap.get("Name"));
	}
	
	@Test
	public void secondMethodOfFirstTestNGClass()
	{
		System.out.println("Executing secondMethodOfFirstTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
		System.out.println("Value of name is :"+ sharedVariablesMap.get("Name"));
	}
}

SecondTestNG class

package SecondTestNullPointerExceptionWithSingleton;

import org.testng.annotations.Test;

public class SecondTestNGClass extends Setup{
	
	@Test
	public void firstMethodOfSecondTestNGClass()
	{
		System.out.println("Executing firstMethodOfSecondTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
		System.out.println("Value of name is :"+ sharedVariablesMap.get("Name"));
	}
	
	@Test
	public void secondMethodOfSecondTestNGClass()
	{
		System.out.println("Executing secondMethodOfSecondTestNGClass...");
		System.out.println("Value of someVariable is : "+ sharedVariables.getSomeVariable());
		System.out.println("Value of name is :"+ sharedVariablesMap.get("Name"));
	}
}

There is no change in TestNG xml.

Output
[RemoteTestNG] detected TestNG version 7.0.1
Executing setupVariable...
Executing firstMethodOfFirstTestNGClass...
Value of someVariable is : someValue
Value of name is :Amod
Executing secondMethodOfFirstTestNGClass...
Value of someVariable is : someValue
Value of name is :Amod
Executing firstMethodOfSecondTestNGClass...
Value of someVariable is : someValue
Value of name is :Amod
Executing secondMethodOfSecondTestNGClass...
Value of someVariable is : someValue
Value of name is :Amod

===============================================
Suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================

You can download/clone the above sample project from here.

If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning

Find all Selenium related posts here, all API manual and automation related posts here, and find frequently asked Java Programs here.

Many other topics you can navigate through the menu.

1 thought on “How To Use Singleton Class to Manage Instance Variables in Automation Framework – Java”

Leave a Reply

Your email address will not be published. Required fields are marked *