Test Listeners (Test Hooks)

here is the code…

import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject

import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testobject.TestObject as TestObject

import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile

import internal.GlobalVariable as GlobalVariable

import com.kms.katalon.core.annotation.BeforeTestCase
import com.kms.katalon.core.annotation.BeforeTestSuite
import com.kms.katalon.core.annotation.AfterTestCase
import com.kms.katalon.core.annotation.AfterTestSuite
import com.kms.katalon.core.context.TestCaseContext
import com.kms.katalon.core.context.TestSuiteContext

class NewTestListener {
	/**
	 * Executes before every test case starts.
	 * @param testCaseContext related information of the executed test case.
	 */
	@BeforeTestCase
	def sampleBeforeTestCase(TestCaseContext testCaseContext) {
		println "Running before the test case runs"
		/*println testCaseContext.getTestCaseId()
		println testCaseContext.getTestCaseVariables()*/
		GlobalVariable.testname=testCaseContext.getTestCaseId()
		String[] tarray=testname.split("/")
		Integer sz=tarray.length
			testname=tarray[sz-1]
			println "test case name is:" + testname
			}
}

Log

2019-10-23 18:50:48.785 INFO  c.k.katalon.core.main.TestCaseExecutor   - --------------------
2019-10-23 18:50:48.790 INFO  c.k.katalon.core.main.TestCaseExecutor   - START Test Cases/ESB Regression/Iteration1/Awarex sample test
2019-10-23 18:50:49.040 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) businessid = JM
2019-10-23 18:50:49.051 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) channelid = CRM
2019-10-23 18:50:49.059 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) accountno = 157168020000
2019-10-23 18:50:49.069 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) fromdatetime = 
2019-10-23 18:50:49.075 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) todatetime = 
2019-10-23 18:50:49.082 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) usagetype = 
Running before the test case runs
2019-10-23 18:50:49.185 ERROR c.k.k.core.context.internal.TestHooker   - ❌ Variable 'testname' is not defined for test case.
2019-10-23 18:50:49.309 DEBUG testcase.Awarex sample test              - 1: println("now running test case:" + testname)
2019-10-23 18:50:49.314 ERROR c.k.katalon.core.main.TestCaseExecutor   - ❌ Test Cases/ESB Regression/Iteration1/Awarex sample test FAILED.
Reason:

Also how do i run the listener script alone. Every time when i want to check listener script i had to run my test.

Hi, please change testname (and the following occurrences) to GlobalVariable.testname.

Hi,

I think you didn’t get the question. The script I shared you is a listener script. below is the main script calling listener script. Also

&&&&&&&&&&main test case script&&&&&
//default packages
import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.cucumber.keyword.CucumberBuiltinKeywords as CucumberKW
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import internal.GlobalVariable as GlobalVariable
import groovy.json.JsonSlurper as JsonSlurper

println “now running test sample testcase:” + GlobalVariable.testname
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Hi, the error is stated in the log above as:

Which is why I asked you to change the name of the variable testname.

You cannot.
A listener is just a class implementing some methods.
Based on the given annotation (@BeforeTestCase etc) the given method it is ‘hooked’ at compile time, aka scheduled in the runtime at the indicated stage.
Therefore it is not possible to run it directly, but by running the scoped script: testcase or testuite.

thanks, this answers it. Is there any other place in katalon where I can copy my listener scripts(the code part excluding annotations) and see if they are working, without running the tests

it didn’t work even after changing the variable name as shown in the mainscript. can you copy the code and run for yourself, so that it will be easy to find out the issue.

I successfully used the global variable set in Test Listener. Please check if you’re doing the following:

Assuming you have a Global Variable called testCaseName created in the Default profile.

TestListener

	@BeforeTestCase
	def sampleBeforeTestCase(TestCaseContext testCaseContext) {
		GlobalVariable.testCaseName = testCaseContext.getTestCaseId();
	}

Test Case which in this case is “Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener”

testName = GlobalVariable.testCaseName

println testName;

assert testName == 'Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener'

Where testName is defined as a Test Case Variable of type string

The console log is:

2019-10-24 16:29:16.843 INFO  c.k.katalon.core.main.TestCaseExecutor   - START Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener
2019-10-24 16:29:17.168 INFO  c.k.katalon.core.main.TestCaseExecutor   - (Default) testName = 
2019-10-24 16:29:17.283 WARN  c.k.katalon.core.logging.KeywordLogger   - Please use "KeywordUtil.logInfo()" instead of "new KeywordLogger()" constructor. "KeywordLogger" is an internal API and might be changed in the future.
2019-10-24 16:29:17.562 DEBUG use global variable set in Test Listener - 1: testName = testCaseName
2019-10-24 16:29:17.563 DEBUG use global variable set in Test Listener - 2: println(testName)
Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener
2019-10-24 16:29:17.578 DEBUG use global variable set in Test Listener - 3: assert testName == "Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener"
2019-10-24 16:29:17.583 INFO  c.k.katalon.core.main.TestCaseExecutor   - END Test Cases/Misc Test Cases/Should be able to use global variable set in Test Listener

@ThanhTo your code should work also without declaring the testName variable in the variable tab.
the script should simply use a local instance instead of a public one in this case

another setup can be to change the variable type in the testcase to the declared global (and remove the assignment line from the script). that should work also fine.
sorry, i am not near my pc to reproduce those scenarios, but if you are not bussy you can play

Yes, it also works without explicitly declaring a Test Case variable. Just put it there to encourage best practices to make test cases parameterized :sweat_smile:.

1 Like

best practice in this case will be the second scenario I suggested.
will still use the global, but can be overriden by a certain passed value if needed.
with your example will allways use the global (the public instance of the variable is bypassed == sort of indirect hardcoding)

1 Like

thanks for looking into this. I wasn’t knowing that global variable has to be defined in profile(default/any profile). After I defined it in profile it worked. I was thinking that just using Global. will make any variable scope as global but not knowing that it has to be there in profile.

How to use @BeforeMethod in Test Listeners.
Basically I wanted to call a function for each customkeyword.

eg:
Function :
def flag()
{
def flag = ‘alfha’
}

Test case :
CustomKeywords.‘beta.Login.OpenBrowser’()
CustomKeywords.‘beta.Offerings.clickCreateNewOffering’()
CustomKeywords.‘beta.Login.closeBrowser’()

In the above example, I wanted to hit ‘flag()’ method / function before each customKeyword step / line while execution.
Can anyone please help me out to find the solution.