When static methods should be used in Custom Keywords?

As per Introduction to Custom Keywords | Katalon Docs,

As per Custom Keywords Refactoring | Katalon Docs ,

How do you know when static methods should be used in Custom Keywords and when static shouldn’t be used?

Short answer:

As far as you call the method in a Test Case with the following syntax:

CustomKeywords."fullyqualifiedclassname.method"(args)

then static modifier of the method is insignificant. With static or without static does not make any difference.


I can show you an example.

A Keyword class my.KwPublicConstructorWithNonstaticMethod which has non-static metod:

package my

public class KwPublicConstructorAndNonstaticMethod {

	public KwPublicConstructorAndNonstaticMethod() {
		println KwPublicConstructorAndNonstaticMethod.class.getName() + " was constructed"
	}

	public String greeting(String name) {
		return "Hello, ${name}!"
	}
}

Another Keyword class with my.KwPublicConstructorAndStaticMethod which has static method:

package my

public class KwPublicConstructorAndStaticMethod {

	public KwPublicConstructorAndStaticMethod() {
		println KwPublicConstructorAndStaticMethod.class.getName() + " was constructed"
	}

	public static String greeting(String name) {
		return "Hello, ${name}!"
	}
}

A Test Case TC1

println CustomKeywords."my.KwPublicConstructorAndNonstaticMethod.greeting"('Earth')
println CustomKeywords."my.KwPublicConstructorAndStaticMethod.greeting"('Moon')

When I ran that TC1, I got the following output:

my.KwPublicConstructorAndNonstaticMethod was constructed
...
Hello, Earth!
...
my.KwPublicConstructorAndStaticMethod was constructed
...
Hello, Moon!

As you can see, these 2 Keyword classes work just the same.

1 Like

Let me show you another example, that would be interesting for a novice Java/Groovy programmer.

A Keyword class my.KwPrivateConstructorAndStaticMethod

package my

public class KwPrivateConstructorAndStaticMethod {

	private KwPrivateConstructorAndStaticMethod() {
		println KwPrivateConstructorAndStaticMethod.class.getName() + " was constructed"
	}

	static String greeting(String name) {
		return "Hello, ${name}!"
	}
}

And I made a Test Case TC2:

import my.KwPrivateConstructorAndStaticMethod as kw

println kw.greeting('John')

When I ran TC2, I got:

2021-02-15 10:30:51.638 INFO  c.k.katalon.core.main.TestCaseExecutor   - START Test Cases/TC2
2021-02-15 10:30:52.496 DEBUG testcase.TC2                             - 1: println(KwPrivateConstructorAndStaticMethod.greeting("John"))
Hello, John!
2021-02-15 10:30:52.546 INFO  c.k.katalon.core.main.TestCaseExecutor   - END Test Cases/TC2

TC2 demonstrates that you do not necessarily use the CustomKeywords."fullyqualifiedclassname.method"(args) syntax. TC2 is a usual Groovy script. It worked.

1 Like

One more example. This would give you an insight how CustomKeywords work. This is meant for an expert Groovy programmers.

I made a Keyword class my.KwPrivateConstructorAndStaticMethod:

package my

public class KwPrivateConstructorAndStaticMethod {

	private KwPrivateConstructorAndStaticMethod() {
		println KwPrivateConstructorAndStaticMethod.class.getName() + " was constructed"
	}

	static String greeting(String name) {
		return "Hello, ${name}!"
	}
}

I made a Test Case TC3:

println CustomKeywords."my.KwPrivateConstructorAndStaticMethod.greeting"('Paul')

When I ran the TC3, I got:

2021-02-15 10:41:47.044 DEBUG testcase.TC3                             - 1: println(my.KwPrivateConstructorAndStaticMethod.greeting("Paul"))
2021-02-15 10:41:47.080 ERROR k.k.c.m.CustomKeywordDelegatingMetaClass - ❌ Class com.kms.katalon.core.main.CustomKeywordDelegatingMetaClass can not access a member of class my.KwPrivateConstructorAndStaticMethod with modifiers "private"
2021-02-15 10:41:47.085 ERROR c.k.katalon.core.main.TestCaseExecutor   - ❌ Test Cases/TC3 FAILED.
Reason:
java.lang.IllegalAccessException: Class com.kms.katalon.core.main.CustomKeywordDelegatingMetaClass can not access a member of class my.KwPrivateConstructorAndStaticMethod with modifiers "private"
	at com.kms.katalon.core.main.CustomKeywordDelegatingMetaClass.invokeStaticMethod(CustomKeywordDelegatingMetaClass.java:46)
	at TC3.run(TC3:1)
	at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
	at com.kms.katalon.core.main.ScriptEngine.runScriptAsRawText(ScriptEngine.java:119)
	at com.kms.katalon.core.main.TestCaseExecutor.runScript(TestCaseExecutor.java:398)
	at com.kms.katalon.core.main.TestCaseExecutor.doExecute(TestCaseExecutor.java:389)
	at com.kms.katalon.core.main.TestCaseExecutor.processExecutionPhase(TestCaseExecutor.java:368)
	at com.kms.katalon.core.main.TestCaseExecutor.accessMainPhase(TestCaseExecutor.java:360)
	at com.kms.katalon.core.main.TestCaseExecutor.execute(TestCaseExecutor.java:255)
	at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:114)
	at com.kms.katalon.core.main.TestCaseMain.runTestCase(TestCaseMain.java:105)
	at com.kms.katalon.core.main.TestCaseMain$runTestCase$0.call(Unknown Source)
	at TempTestCase1613353293369.run(TempTestCase1613353293369.groovy:25)

An Exeption was raised at at com.kms.katalon.core.main.CustomKeywordDelegatingMetaClass.invokeStaticMethod(CustomKeywordDelegatingMetaClass.java:46). You can read the source code at

If you read the source code carefully at Line#46 - 50, you can find the following points.

  1. Line#46: CustomKeywordDelegatingMetaClass calls the constructor of the Keyword class to create an instance of the Keyword class. The caller requires a public constructor with no arguments. In the case of my.KwPrivateConstructorAndStaticMethod class, it lacks a public constructor; therefore an Exception is raised.
  2. Line#50: CustomKeywordDelegatingMetaClass invokes a method of name customKeywordMethodName regardless if the method is static or non-static.
  3. Line#36: The method is named as invokeStaticMethod. But I think the method should rather be named as invokeMethod, because the method can actually deal with both cases where the method is with or without static modifier.

I guess that the Katalon programmer who originated this code had static modifier in mind, but he/she eventually wrote something slightly different from the original idea.

===================

Let me write the last possible case. Another Keyword class with a private constructor and a public instance method (non-static method):

package my

public class KwPrivateConstructorAndNonstaticMethod {

	private KwPrivateConstructorAndNonstaticMethod() {
		println KwPrivateConstructorAndStaticMethod.class.getName() + " was constructed"
	}

	String greeting(String name) {
		return "Hello, ${name}!"
	}
}

A Test Case TC4:

import my.KwPrivateConstructorAndNonstaticMethod as kw
println kw.greeting('George')

When I ran TC4, I got error (as I expected):

2021-02-15 15:40:18.199 INFO  c.k.katalon.core.main.TestCaseExecutor   - START Test Cases/TC4
2021-02-15 15:40:19.266 DEBUG testcase.TC4                             - 1: println(KwPrivateConstructorAndNonstaticMethod.greeting("George"))
2021-02-15 15:40:19.312 ERROR c.k.katalon.core.main.TestCaseExecutor   - ❌ Test Cases/TC4 FAILED.
Reason:
groovy.lang.MissingMethodException: No signature of method: static my.KwPrivateConstructorAndNonstaticMethod.greeting() is applicable for argument types: (java.lang.String) values: [George]
Possible solutions: greeting(java.lang.String), getAt(java.lang.String)
	at TC4.run(TC4:2)
	at com.kms.katalon.core.main.ScriptEngine.run(ScriptEngine.java:194)
....

This class (with a private constructor and a public instance method) never works. It is just useless.

1 Like

Thanks a lot for your replies! As per your quote above, my current understanding is that either static or non-static method will be invoked. What I’m trying to understand is why in Samples (provided by Katalon) static is not used

but in the sample project (provided by Katalon as well) static is used:

I’m trying to figure out what’s made Katalon use static in the second case but not in the first one.

If it wasn’t done randomly (I hope not)), are there any practical reasons for that?

More here.

In the case of keyword classes, static allows you to import the classes and call their methods directly, without the need to wrap them as string properties of the CustomKeywords class(es).

// long stringy name
CustomKeywords."classname.methodname"(args)

// call directly
methodname(args)

In Katalon, what this amounts to is, your statically imported methods become “global methods”, and, like the docs say, they act as if defined in your own (local) class. Your local class is the class you never see that “hosts” or wraps your TC.

Read that again - your TC is essentially the “body” of a run method defined on a Script Class.

1 Like

Thank you, Russ. Do you happen to know the answer to my question at When static methods should be used in Custom Keywords? as well:

"what’s made Katalon use static in the second case but not in the first one.

If it wasn’t done randomly (I hope not)), are there any practical reasons for that?"

As already explained there is no real benefit in using static modifier if you invoke in TC through the CustomKeyword wrapper.
Most probably the discrepancy in the docs is due to various developers updating the docs.
Devs are using copy-paste too, not only mortals.
More devs, more habits.
And it is known that devs are the the worst tech writers :stuck_out_tongue:

Precisely that. Occam’s razor and all that.

Bionell, I have a confession to make. The reason why I created this topic is because I was trying to implement POM as per Page Object Model :

Page Object Model :

Franco is not using static but in the Katalon sample projects static is used :

The problem is that when I was running the tests I created as per Franco’s approach (w/o static) in PARALLEL mode some tests are failed. When I was running the tests from Katalon sample (Shopping Card, static is used in the keywords) in PARALLEL mode, there was no problem. So, I was thinking that static might be needed in order to be able to run tests in PARALLEL in Katalon (even though it goes against all my previous experience with Java, but the truth is that I have no idea how Groovy and Katalon work “under the hood” and when instances of those “keyword” classes are created (if ever) )

@gdearest07

I think you’re chasing a noble quest. Noble, but not pragmatic.

<rant>
Keep in mind your test code is fleeting - it’s not “running all day”, it dies fairly quickly. So some of the “best practices” (a phrase that really annoys me) are best left to the people who think they matter and who think they actually mean more than they do. Meanwhile, I’m having a beer.

Would I fill my code with static stuff if it were running the international banking system or moderating aircraft in a holding pattern around JFK? Hell no.

It’s TEST CODE. It lives and dies and memory is cleaned up (usually) all in a matter of minutes. I use statics everywhere. All my keywords are static - every single one of them (there are a couple thousand, I’m sure).

Best practices? YAGNI. Move on. Go write code.
</rant>

1 Like

I should say 'there is no benefit if you invoke it only in testcases.
However, static modifier may have sense if you use a class (custom keyword) in another class (another custom keyword or a class defined in TC)

1 Like

Thanks, Russ. It’s a good quote. Should we come to the conclusion that the “best practice” would be always use static for keywords (in Katalon Studio))?

You’re not listening. I don’t favor “best practice” any more than I can define it in a short and meaningful sentence or tell you what it is.

What I can tell you is, I use static methods and static imports everywhere.

If that’s worth anything, you tell me.

Here’s what my test cases look like…

image

A post was split to a new topic: Please define Best Practice

I do listen, Russ. That’s why I put “best practice” in the double quotes (and put ‘))’ at the end))

As an example, I do it exactly opposite. I never use a certain modifier or keyword unless i realy need it in my code.
E. G. i never use def variable in a testcase, because is just script. I simply assign the variable if not already defined at a certain above level.
But most of the people do use the def no matter if it is a class or script.
Sometime it is only about practice :smiley:

Sure, Bionel. I know what you mean. I wouldn’t never ask these questions it it were not for that problem while running tests in parallel (When static methods should be used in Custom Keywords?). When I was doing automation in Java I tried to avoid using static in order to have fewer problems with multithreading

Well, ok.
But aside of the theory, do you have a working code?
If yes, please share it with us and we can look on it to see if it can be improved.
If not, first focus on writing functional code.
That is also part of ‘best practice’.
Write something, make it reliable, review, optimise.

L. E. Trust me, the worst one can do is attempt to write optimised code from the begining. You will never end your current task :smiley: