What is the best practice to write the test results of each test targets in a Test Case to Excel file?

Hi,

I’m trying to write the test results of the each test targets in a Test Case to Excel file.

Assumption:
I manage that a Test Case is composed of each test targets.
Because the volume of each test targets are too enormous, so I can not manage one test target as one Test Case.

Current situation:
Here is a example of writing test results of each test targets to Excel file.
To write the test results of test targets, I use try-catch every time, but that is too tedious.

WebUI.openBrowser('')

// test target 1: bundle click and getText to regard as a test target
try{
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product1'))
	CustomKeywords.'com.helper.excel.ExcelHelper.writeToExcelFile'('C:\\\\Users\\\\xxxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
	'succeeded!', 1, 1)
} catch(Exception e) {
	CustomKeywords.'com.helper.excel.ExcelHelper.writeToExcelFile'('C:\\\\Users\\\\xxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
	'failed!', 1, 1)
}

// test target 2
try{
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product2'))
	CustomKeywords.'com.helper.excel.ExcelHelper.writeToExcelFile'('C:\\\\Users\\\\xxxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
	'succeeded!', 1, 2)
} catch(Exception e) {
	CustomKeywords.'com.helper.excel.ExcelHelper.writeToExcelFile'('C:\\\\Users\\\\xxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
	'failed!', 1, 2)
}

// and so on...

WebUI.closeBrowser()

So please tell me the best practice to write the test results of the each test targets to Excel file in a Test Case.
Sorry for my poor English.

Best regards.

You can develop a custom keyword for yourself. See

Your custom keyword will have a try … catch, and will accept a few parameters (Test Object, File path etc). Your test case will call your custom keyword passing parameter values as often as you want. Provided with the custom keyword, your test case code can get fit, no tedious any more.

1 Like

Thankyou!
I’ll try that.

you can implement an AfterTestCase listener and retrieve the testcase status with testCaseContext.getTestCaseStatus().

see: https://docs.katalon.com/katalon-studio/videos/test_listeners_test_hooks.html

see also related topics:

1 Like

@kazurayam
@bionel
Thank you!

But I’d like to write each test result in multiple try-catch blocks in a TestCase to Excel file.
So using testCaseContext.getTestCaseStatus(), only one test result in a TestCase is appeared .


Now I’m trying to use Custom Keyword to write try-catch block inside it,
but can’ t pass methods(WebUI. click, getText, etc) to Custom Keyword.

What I expect is that Custom Keyword catches param(click, getText) to execute try-catch so that it’ll be easy to write TestCase without writing try-catch every time.

Is there way to pass methods to Custom Keyword or other way to write efficiently ?

In Groovy language, you can create Closures, similar to Java 8’s Lambdas. You can create an instance of Closure and pass the Closure object as an argument to a Groovy class method call.

Katalon’s TestCase scripts is almost a Groovy script. It might be an idea to try using Closures as parameter to Custom Keyword.

However I have never tried Closures as argument type from Katalon TestCase script to Custom Keyword. The TestCase compiler may complain about it somehow. it is unpredictable. Just try it and see.

1 Like

Possibly you do not even need Custom Keyword at all. You can define a Groovy method inside a TestCase script and instantly use it.

In a Katalon TestCase, write

// define a method
def add(a, b) {
    a + b
}

// call a method
def val = add(100, 200)
println val

and run it. It should work and will print 300

1 Like

@kazurayam
Thank you so much.
Using Closure like anonymous function, each test result are caught.

You can define a Groovy method inside a TestCase script and instantly use it.

It might be nice idea, but I’d like to use try-catch block and to write to Excel file in multiple TestCases.

Currently, there is a thing to improve that every time closure is defined,
Custom Keyword should be called, because a rowNo and a colNo are always different.
So I’ll try to refactor.

Custom Keyword

    @Keyword
	def writeTestResultToExcel(Closure closure, int rowNo, int colNo) {
		try{
			closure()
			println 'succeeded!'
			writeToNewExcelFile('C:\\\\Users\\\\xxxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
					'succeeded!', rowNo, colNo)
		} catch(Exception e) {
			println 'failed!'
			writeToNewExcelFile(C:\\\\Users\\\\xxxxxx\\\\Downloads\\\\testResults.xlsx', 'TestData',
					'failed!', rowNo, colNo)
		}
	}

TestCase

def firstTestTarget = { 
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product1'))
	// do something 
}
CustomKeywords.'excel.ExcelHelper.writeTestResultToExcel'(firstTestTarget, 1, 1)

def secondTestTarget = { 
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product2'))
	// do something
}

CustomKeywords.'excel.ExcelHelper.writeTestResultToExcel'(secondTestTarget, 2, 2)

ah, got it, in fact you need the status of each test step.
yeah, in this case your approach seems to be fine.

1 Like

A short example making use of Closure syntax in Katalon TestCase script.

// define a method
def calcurate(Closure closure) {
	try {
		closure()
	} catch (Exception e) {
		println "My bad!"
	}
}

// call the method with variety of Closures
println calcurate({ a=100, b=200 -> a + b })
println calcurate({ a=100, b=200 -> a - b })
println calcurate({ a=100, b=200 -> a * b })
println calcurate({ a=100, b=200 -> a / b })
println calcurate({ a=100, b=0   -> a / b})

Result:

300
...
-100
...
20000
...
0.5
...
My bad!
null
1 Like

@bionel
Yes, step !
Thank you.

@kazurayam
Thank you as always.
Your tips made me to write effectively.
I got to the result to include closure in CustomKeyword argument.

CustomKeywords.'excel.ExcelHelper.writeTestResultToExcel'({
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product1'))
	// do something 
    // do something
}, 1, 1)

CustomKeywords.'excel.ExcelHelper.writeTestResultToExcel'({
    WebUI.click('Object/xxxxx')
	println WebUI.getText(findTestObject('Object Repository/header/em_product2'))
	// do something
    // do something
}, 2, 2)

After all, I left the custom keywords in place because every time I must call try-catch block and method to write to Excel file each TestCase.
Last problem is that writeTestResultToExcel method’s second and third arguments(Excel rowNo, colNo) are magic number.
So I’d further correct it.

What do you mean by saying “magic number”? These are not magical at all. These are the row and column where you want to write the info into, isn’t it?

You do not like to specify the rowNo and colNo in the TestCase script at all?

OK. It is easy enough. You want to make your Custom Keyword class stateful so that the object is aware to which Row/Col in an Excel sheet to write a new stuff next time when the writeXXX method is called.

Your Custom Keyword class would be an ordinary stateful Java/Groovy class, which would look like this:

package my

class MyTestResultWriter() {
    private String filepath
    private int rowNo
    private int colNo
    MyTestResultWriter(String filepath) {
        this.filepath = filepath
        assert this.filepath != null
        // here you may want to create a File object for Excel .xlsx and instanciate a Workbook object, possibly
        rowNo = 0
        colNo = 0
    }
    void writeTestResultToExcel(Closure closure) {
        rowNo++
        colNo++
        try {
            ....
           writeStuff('succeeded!', rowNo, colNo)
        } catch (Exception e) {
            ....
            writeStuff('failed!', rowNo, colNo)
        }
    }
}

Remember, your test case code needs to instantiate the class object.

import my.MyTestResultWriter

def trw = new MyTestResultWriter("file path")

trw.writeTestResultToExcel({ -> /* do something*/})  // rowNo=1
trw.writeTestResultToExcel({ -> /* do something more*/})  // rowNo=2
trw.writeTestResultToExcel({ -> /* do something even more*/})  // rowNo=3
1 Like

Opening/closing a Excel file every time you write a line of message, and repeating it many times ---- it would cause a performance problem. You should minimise the number of times your code open/close a xlsx file

1 Like

@shunmatsu_begginer

Please find that my sample code of MyTestResultWriter class lacks the @Keyword annotation.

You may get confused but @Keyword annotation is optional, not required.

In the keywords directory, you can place any ordinary Groovy class source without @Keyword. The @Keyword annotation is just an additive to help Katalon Studio’s GUI aware that the class is a Custom Keyword so that the GUI shows some guidance for programming-beginners.

I do not need any GUI assistance for the MyTestResultWriter class, so I make it a Plain Old Groovy Class without the @Keyword annotation.

1 Like