How to share function between test cases

I’m sure it’s something stupidly obvious, but I can’t quite figure out where to place a method or function to share between test cases.

I want to call it in various test cases to log in. Where do I put the code for this so that multiple test cases can use it? I would guess in a library file, but I’m not quite seeing where it goes.

boolean logIn()
{
WebUI.navigateToUrl(‘http://xx.x.x.xx:8080/CIS/login/APS’)
WebUI.setText(findTestObject(‘Object Repository/Page_APS Test System/input_Username_username’), ‘myUsername’)
WebUI.setEncryptedText(findTestObject(‘Object Repository/Page_APS Test System/input_Password_password’), ‘AHzSUGJgRo0mPVkhbsSVrg==’)
WebUI.click(findTestObject(‘Object Repository/Page_APS Test System/button_SIGN IN’))
return true
}

Im not sure if i have misunderstood what you want to do but what i gather is you simply want to call a test case in another test case -

i would just create a test case called “login” which contains your following code -

{
WebUI.navigateToUrl(‘http://xx.x.x.xx:8080/CIS/login/APS’)
WebUI.setText(findTestObject(‘Object Repository/Page_APS Test System/input_Username_username’), ‘myUsername’)
WebUI.setEncryptedText(findTestObject(‘Object Repository/Page_APS Test System/input_Password_password’), ‘AHzSUGJgRo0mPVkhbsSVrg==’)
WebUI.click(findTestObject(‘Object Repository/Page_APS Test System/button_SIGN IN’))
return true
}

Then in the test case you want to use this script simply start the script with WebUI.callTestCase(findTestObject(“the name of the test case”)). Thats how i do it, i just create a folder in test cases and keep all the re usable scripts in there.

Hope thats what you wanted

Harry

1 Like

It sounds like you want a Custom Keyword (class). If you create one, you can place all your “shared” methods in that class and import that class (file) in whichever tests need it.

https://docs.katalon.com/katalon-studio/docs/introduction-to-custom-keywords.html

4 Likes

Agreed, you want to use Custom Keywords. Here’s some documentation to get you started:

https://docs.katalon.com/katalon-studio/docs/sample-custom-keywords.html

4 Likes

Looks like Custom Keywords are just what I needed! Thank you. Interesting terminology, why is it called that? It seems slightly clunky to write stuff like this, but it it works perfectly:

boolean loggedIn = CustomKeywords.‘myMethods.someMethods.logIn’()

You actually don’t need to use the @Keyword decorator as shown in the examples. You can just implement this like a normal Java/Groovy class and call methods as usual:

public class Login {

    public void login() {
        .
        .
        .
    }
}

In your script, instantiate your “custom keyword” (really, “custom keyword” is just Katalon’s terminology for a “class”) and call method:

new Login().login();

Or you could implement all of your custom keywords as utility classes, and call methods statically:

public class Login {

    private Login() {}

    public static void login() {
        .
        .
        .
    }
}

Called using:

Login.login();

4 Likes

This has really helped me aswell - never knew how the custom keywords worked on here, now i can organise properly

If you’re interested, there’s an extremely efficient way to organize your code called the Page Object Model. I would highly recommend it:

2 Likes

Great thanks for sharing - definately looks like something ill be interested in

Thank you @Brandon_Hein that is very helpful!

I’ve got my code down to this:
new myMethods.SomeMethods().logIn()

But it seems like I have to include the package name (“myMethods”) for it to work properly. Did you skip the package name in your examples somehow?

This is how Java/Groovy works; you must reference your custom keyword (your class) in either of the two following ways:

1.) Include the package name before the class name, as you’ve done (not recommended for most circumstances, see below for why):

new myMethods.SomeMethods().logIn()

2.) Import the package (this is how you should do things 99.9999…% of the time):

Add the following import statement to the top of your script:

import myMethods.SomeMethods

Then call your method the usual way:

new SomeMethods().logIn()

Note: There’s an extremely convenient way to import any packages that the script will need. Simply press ctrl + shift + o, and the studio will pull in all of the required packages based on your current code. If it finds classes in multiple different packages that share the same name, it will ask you to choose which one you want.

In reality, you should only use approach #1 when you need to use two different classes that share the same name. For example, pretend we have two custom keywords called “SomeMethods”, but they exist in different packages:

package package1

public class SomeMethods() {

    public void doSomething() {
    }

}

and

package package2

public class SomeMethods() {

    public void doSomething() {
    }

}

Then in our test case, pretend that we need to use the doSomething() method from both classes for whatever reason. Then calling new SomeMethods() won’t work, because the compiler won’t know which SomeMethods class to use. Should it use the one defined in package1, or the one defined in package2? In this case, you should use approach #1 from above:

new package1.SomeMethods().doSomething();
new package2.SomeMethods().doSomething();

In the real world, you should rarely need to do this. If you find yourself needing to do it quite often, then it’s probably time to take a moment and rename your classes/reorganize packages.

2 Likes

Perfect, thank you so much. And that shortcut to add the needed packages is really handy!

2 Likes

Hi Brandon, is there any practical difference between using 1) new Login().login(); and 2) Login.login();? For example, would either approach work in case of running in Parallel mode? What are use-cases for instantiating of “keyword” classes to use their methods vs. using static methods of “keyword” classes?

There are a few practical differences, yes. Here are a couple:

1.) Static methods are not generally thread-safe. This really only comes into play when you are dealing with mutable objects, but still, it’s standard practice to use instantiable objects and their methods over classes with static methods, whenever possible.
2.) Static methods cannot be overridden, so extending a class with static methods is severely limited in that regard.

At the end of the day, having static methods really just saves you some memory space, but in the grand scheme of things, it’s usually inconsequential.

All of this being said, you could probably use static methods without any issues. It just isn’t “standard practice”, so I don’t write my answers that way :slight_smile:

1 Like

Thank you, Brandon.
What I’m trying to do is to implement POM as per Page Object Model - #4 by francorebu :

Page Object Model - #14 by francorebu :

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

So, I’m trying to figure out whether or not static should be used. Also, I have a couple of questions about his implementation that haven’t been answered yet:

Brandon, my understanding is that you’ve done POM a lot with Katalon. Could you please help me out to figure out the best way to do it? Thanks!

I think the choice to use static keywords or not, in this case, comes down to your individual needs. In our case, we have a lot of “base” keywords that we extend into custom client implementations, so we could not use static methods in our POM. I also just generally like to stick with Java best practices, and instantiate objects as I need them.

In terms of Franco’s code, I haven’t seen it, but I can still answer your questions from my perspective.

1.) “Do you happen to know whether or not a code like yours would be working if a web page corresponding to the POM get’s refreshed…?”

Regardless of the implementation, a keyword must relocate elements in the DOM every time it is called. Otherwise, as you’ve observed, if the page is refreshed, all of your web element references become “stale”, and will throw exceptions if used.

2.) “… do you happen to know whether for every call of keyword (as in your screenshot) a new object of the keyword is created…?”

This is the static vs. non-static methods again. If your keyword is static, it will be loaded into memory once, and could be reused throughout the lifetime of your execution (across multiple test cases in a suite, etc.).

If you instantiate your custom keyword using the new keyword, then an instance (or multiple instances, if you’d like) of that class would be created, which you can either reuse in your test case multiple times, or only once, doesn’t matter. At the end of your test case, that reference will no longer be valid, in which case you would need to re-instantiate in any future scripts in your suite.

1 Like

Brandon, being a Java programmer (and not knowing Groovy)) I “like to stick with Java best practices” too and that’s why I like your approach with initiating custom keyword using the new keyword. In that case it’s clear what’s going on. As for Franko’s implementation I’m not sure what’s going “under the hood” (i.e. whether or not a new Page_Login object is created when some of its keywords is used in a test, etc.) and, as per your reply, my understanding is that would be better to use findTextObject() inside the methods. Can you show a sample of your POM and its usage in a test?

Sure. Let me link you some pseudo code I wrote in another topic a while back ( instead of re-typing it :slight_smile: ):

This is, very generally, my interpretation of a good POM structure.

1 Like