How to use Global Variables between test suites while executing Test Suite Collection?

hi,

check this chain

Global variables works well between test cases in a test suite. How about between test suites?

1 Like

yeah, that’s true, not able to use global variables between testsuites in testsuitecollection.
it always uses default value when testsuite will start
and detected new bug
when executed TSC in console log show only TS one log
TS2 log only blinks there
this is quite buggy release

and what is this popup
popup

ok, console log show testsuite 2 log if not pressed OK

Hi @Chris_Trevarthen
Any update on this?

Hello,

Katalon Studio ver. 7.2.1

Is there any follow up on this?

I have 3 mos work on the line here. I so far can NOT pass a global variable from 1 Test suite collection to another.

This makes no sense Both test suite collections are using the same default profile:

BOTH TEST SUITE COLLECTIONS USE THE SAME PROFILE

Test suite collection 1: defining a global variable getUrl= GlobalVariable.simURL
also defined in default profile: simURL = value type "

this works throughout any script in test suite collection 1

Test suite collection 2: openbrowser simURL - does not work opens a blank browser window.

This should not be a problem, as far as I can tell this is possibly a bug in Katalon?

In fact, make sense if you understand how the profiles are implemented.
The GlobalVariable compiled class which is generated at runtime in the compile phase it is scoped to the suite.
Which means, once the suite ends (no matter if it was started in a collection or standalone) the instance of the generated GlobalVariable class it is destroyed, during the run of the 2nd suite (no matter if it is running sequential or parallel) a new instance for the running thread is created based on the values defined in the selected .xml file (the profile)

So, on short, it is not possible to re-use values set in the selected profile during a suite run for another suite run, even if the selected profile is same (and honestly i see no reason for such feature … but this is just my opinion)

To achieve such goal, you may want to export the needed variables to an external file or a third party db (postgres, mysql, sqlite, whatever) and reuse-them by implementing a custom keyword.

Or … find a way to modify the profile .xml during the execution of the suite.
But pay attention, if you attempt to run the suites in parallel, lot of bad things can happen. And i doubt will work even with sequential execution too … feel free to try.

Thanks for your timely response - IMO this should be a critical feature enhancement, to have the ability to pass global variables.

@Paul_Smith1 well … Here is the time to debate.
You may consider it a critical feature, i don’t.
I do understand from where such behaviour may be desired, being an ex postman user.
And indeed, with postman, the environments (equivalnt to profiles in katalon) are updated ‘on the fly’
However, are updated only for the running instance,to make them permanent you have to export them.
In addition, postman and similar apps are not designed for parallel execution.
In katalon, you can do that (the parallel voodoo). Now let’s imagine that an inexperienced user will abuse it. Lot of stuff can go wrong.

As per myself,i will choose the workarounds i suggested, and i am possitive here @Timo_Kuisma1 can help a lot. He already posted an working example with postgres approach and if he is kind, he can develop a POC on sqlite too (i am lazy to write code).
For the feature request as in your original attempt, we may need to summon some others:

@ThanhTo @devalex88 and yeah, why not, being a great moderator, @Russ_Thomas too

I don’t see Katalon changing the scope of GlobalVariables. If they did, millions of lines of legacy code would suddenly break causing a huge backlash of angry test developers.

Perhaps a proposal for “UniversalVariables” could be made, if one saw the need, that could address the issues you believe are caused by the current scope of GlobalVariables. But even if that were agreed by the devs, it’s not going to happen overnight.

Much quicker would be a set of methods that read/write your data to external files. Personally, I use JSON files. In my case I don’t need to write to them, I only read them and they are managed outside of Katalon.

@Paul_Smith1 If you want to see some groovy code, let me know.

1 Like

Here is a sample code of loading and saving json file:

1 Like

Thanks for the response, I know nothing about groovy, so examples would be great.

In my example Im looking to put GetUrl = GlobalVariable.simURL and use it across multiple test suites. So how would I save the GetUrl into a file, and call it into the next test suite using groovy?

thanks again,

Follow @kazurayam’s advice above.

Okay, on second thoughts, you might need a little more help than @kazurayam’s post provides. Here is my method I use to load my vars. I trust you can take the save routine and beef it up to suit your needs (like I said, I don’t write to this file)

  /**
   * Read in the current profile settings.
   */
  static void loadProfileSettings() {
    String profileName = RunConfiguration.getExecutionProfile()
    comment("testcaseManager.loadProfileSettings: " + profileName)
    String dir = getMyPath()
    def f = new File(dir + "json/" + profileName + ".json")
    Map map = new JsonSlurper().parseText(f.text)
    GLOBALS << map
  }

GLOBALS is a statically declared map which I make sure is available everywhere.

  static Map GLOBALS = [:]

The last line stores the entire JSON structure (map) into the GLOBALS map

2 Likes

Opened a ticket. Thanks guys for your suggestions

Personally, I think because Test Suites are meant to be executed in parallel, enabling this type of shared states between them would possibly open the door to multitudes of concurrency problems. Nonetheless, I’d update if this ever makes to the approval stage.

4 Likes

It would be nice if Test Suites and Test Suite Collections had their own properties pages (like Test Cases have). I store TC-related data in the property description field. If TSCs had those, they could be used to read/write data that can then be viewed post execution if need be.

Sometimes it’s worth thinking inside the box :wink:

Thanks very much for your help Russ. Question: Does the code you provided get put into the “profile” for example if Im using the default profile, I would edit the default profile and add the code to it? Or would I create a new profile for every test suite collection and add the code to each new profile?

thanks again for all your help in this matter.

No. Despite the name, it does NOT touch your Katalon profile, it uses the same name to keep things “straight”, that’s all.

This…

String profileName = RunConfiguration.getExecutionProfile()

does what it says it does, grabs the “name”. That’s just a string, If yours are all called “StuffAndThings” that’s fine too.

Hi,
I know this is an “old” topic. But just my 2cents: I have written a custom keyword that allows writing a property to an excel and later on when I need it to read from that excel the propertyValue. In theory, it can be used across Test Suites. I use it for 2 test cases that run in the same test suite.

Setup:
In my global profiles I have a property called "transferPropertiesPath " that with value the folder that contains the excel defined in my test data = “transferPropertiesToExcel.xlsx”.

In the setup script of the testSuite I run below code to first clear all worksheets from the excel.

@SetUp(skipped = false) // Please change skipped to be false to activate this method.
def setUp() {
	try{
		File file = new File (TestDataFactory.findTestData(GlobalVariable.transferPropertiesPath).sourceUrl)
		boolean exist = file.exists()
		if (exist){
			FileInputStream inFile = new FileInputStream (new File (TestDataFactory.findTestData(GlobalVariable.transferPropertiesPath).sourceUrl))
			XSSFWorkbook workbook = new XSSFWorkbook(inFile);
			XSSFSheet sheet
			int numberOfSheets = workbook.getNumberOfSheets()
			KeywordUtil.logInfo('Setup script - TransferPropertiesToExcel numberOfSheets = ' + numberOfSheets.toString())
			for (int i = 1; i<= numberOfSheets; i++){
				workbook.removeSheetAt(numberOfSheets-i)
			}
			workbook.createSheet('sheet')
			inFile.close();
			FileOutputStream outFile = new FileOutputStream(new File(TestDataFactory.findTestData('Mortgage/i18n/transferPropertiesToExcel').sourceUrl));
			workbook.write(outFile);
			outFile.close()
		}
	}
	catch(Exception ex) {
         println("Catching the exception in Setup script CreateFullRequest");
    } 
}

The actual Keywords script in TransferProperties.groovy =

package be.fednot.common.test.support.katalon
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRow
import com.kms.katalon.core.annotation.Keyword
import com.kms.katalon.core.testdata.TestDataFactory
import com.kms.katalon.core.util.KeywordUtil
import com.kms.katalon.core.testdata.reader.ExcelFactory

import internal.GlobalVariable

class TransferPropertiesToExcel {
	/**
	 * Transfer the given parameter name and it's value to an excel in the transferPropertiesPath defined in the profile.
	 */
	@Keyword
	def transferPropertiesToExcel(String parameter, String value) {
		try{
			FileInputStream file = new FileInputStream (new File (TestDataFactory.findTestData(GlobalVariable.transferPropertiesPath).sourceUrl))
			XSSFWorkbook workbook = new XSSFWorkbook(file);
			XSSFSheet sheet
			String testName = GlobalVariable.currentTestCaseId
			//KeywordUtil.logInfo("GlobalVariable.currentTestCaseId = " + testName)
			if (testName != '' && testName != null){
				def index = workbook.getSheetIndex(testName.take(31))
				if (index < 0){
					KeywordUtil.logInfo "TransferPropertiesToExcel : testName.take(31) = " + testName.take(31) + ". Create sheet because index = - 1 --> "+ index
					sheet = workbook.createSheet(testName)
				}
				else{
					sheet = workbook.getSheetAt(index)
				}
			}
			else{
				sheet = workbook.getSheetAt(0);
			}

			int numberOfRows = sheet.getPhysicalNumberOfRows()
			if(numberOfRows == 0){
				XSSFRow headerRow = sheet.createRow(0)
				headerRow.createCell(0).setCellValue("parameter")
				headerRow.createCell(1).setCellValue("value")
			}
			XSSFRow currentRow = sheet.createRow(sheet.getLastRowNum()+1)
			currentRow.createCell(0).setCellValue(parameter);
			currentRow.createCell(1).setCellValue(value);

			file.close();
			FileOutputStream outFile =new FileOutputStream(new File(TestDataFactory.findTestData('ABC/i18n/transferPropertiesToExcel').sourceUrl));
			workbook.write(outFile);
			outFile.close()
		}catch (FileNotFoundException ex) {
			KeywordUtil.markWarning("FileNotFoundException on the TransferPropertiesToExcel! The file should NOT be open during run. We are not storing properties in the excel!")
		}catch (Exception ex) {
			KeywordUtil.markWarning("General exception (not FileNotFoundException)  on the TransferPropertiesToExcel! We are not storing properties in the excel!")
		}
	}

	@Keyword
	def getValueFromExcel (String parameter, String sheetName){
		//create an instance. . . .
		//the last parameter (boolean) allows your first row to become a column name so that it //will be easy for you to define which column you are accessing. If false, it will be //counted as an excel record. And you don’t have any identification which column you //want to get. So I suggest making it true (it depends on your test).

		try{
			Object excelData = ExcelFactory.getExcelDataWithDefaultSheet(TestDataFactory.findTestData(GlobalVariable.transferPropertiesPath).sourceUrl, sheetName, true)

			List<List<Object>> allData = excelData.getAllData()
			int dataLength = allData.size()
			//KeywordUtil.logInfo("dataLength = " + dataLength.toString())
			boolean isParameter = false
			for(int i=0; i<dataLength; i++){
				List<String> row = allData.get(i);
				isParameter = row.get(0).equals(parameter)
				if (isParameter){
					def value = row.get(1)
					KeywordUtil.logInfo("Parameter \"$parameter\" found! Returned value on row $i = " + value)
					return value
				}
			}
			KeywordUtil.markWarning("No value found for parameter $parameter in the excel with $sheetName! The total number of rows is $dataLength.")
		} catch (FileNotFoundException ex) {
			KeywordUtil.markWarning("FileNotFoundException on the TransferPropertiesToExcel! The file should NOT be open during run. We are not storing properties in the excel!")
		} catch (Exception ex) {
			KeywordUtil.markWarning("General exception (not FileNotFoundException)  on the TransferPropertiesToExcel! We are not storing properties in the excel!")
		}
	}
}

To write a property to the excel:
CustomKeywords.‘be.fednot.common.test.support.katalon.TransferPropertiesToExcel.transferPropertiesToExcel’(‘parameterNameYouWantToSet’, parameterValue)

To get a property from the excel:
CustomKeywords.‘be.fednot.common.test.support.katalon.TransferPropertiesToExcel.getValueFromExcel’(‘parameterNameYouWantToGet’, ‘worksheetOfExcelYouWantToTarget’)