Calling Custom Java Code in Karate API Tests

Hello, a few months ago, Ali Aktolun briefly explained how to use Karate Framework for web service testing. Here’s the article. You need to be familiar with Karate in order to understand the Calling Custome Java Code in Karate API Tests tutorial.

The most important feature of Karate isno coding”. But there are cases where you need to take custom actions like saving a response to a file, file reading or writing, etc. In this tutorial, I’ll explain how to use Java codes in Karate API tests and Karate Projects.

My use case is testing web services which require authentication. My first web service does the authentication and creates a token, then all other services use that token. But generated token belongs to “Authentication test” context. When I execute the next web service, this token is not recognized as it belongs to previous test context. So what should I do?

  • I can use Karate’s built-in call method. This method will call “Authentication Service” before execution of any other scenarios. So I will have multiple web service calls which will increase execution time.
  • I can save generated token in a file. Then I read this token before other scenario’s execution. By this way, I will run the “Authentication Service” once.

Maybe there are other smart solutions to do that but this is the second one is the one I come up with to reduce the execution time for Java Code in Karate API Tests.

Implementing Java Code

Let’s start from Java Code that writes to and reads from a properties file. This code simply writes our token to config.properties file by using write method. Then you can read the value by using read method.

public void write(Map<String, Object> config) throws IOException {
     String key = (String) config.get("key");
     output = new FileOutputStream(FILE_NAME);
     prop.setProperty("key", key);
     prop.store(output, null);
}

Write method takes a Map<String, Object> object as an input. I can send a key and its corresponding value as parameters by having this object. In case you want to send one String value, you can change your method signature as below. Implementation depends on you.

public String read(String key) throws IOException {
     input = new FileInputStream(FILE_NAME);
     prop.load(input);
     return prop.getProperty(key);
}

Read method only read from the config file by using a key value. As I only send one String, method signature is different than the previous one.

Calling JAVA Code in Karate API Tests

Here’s my test code that creates a token from the authentication server.

Scenario: Login to Loadium
     Given url 'https://account.loadium.com/uaa/oauth/token?grant_type=password&password=PASS&username=USER&scope=openid'
     And header Accept = 'application/json'
     And header Authorization = 'Basic dGVzdGluaXVtU3VpdGVUcnVzdGVkQ2xpZW50OnRlc3Rpbml1bVN1aXRlU2VjcmV0S2V5'
     And request {}
     Then method POST
     Then status 200
     * def token = $.access_token

I need to call write method in this scenario to store generated token into a file.

Defining File Write Functionality

* def doStorage =
"""
function(args) {
     var DataStorage = Java.type('examples.DataStorage');
     var dS = new DataStorage();
     return dS.write(args);
}
"""

This command creates an object with doStorage name that you will use in your Karate DSL test. Blue ones are the name of my Java file. The green one is the package name of my Java class. As you can see we create a variable dS then call write method. This is the method name that we have in Java class.

Calling File Write Functionality

I add the below line to my scenario.

* def result = call doStorage {'key': #(token)}

call is a built-in component of Karate framework. doStorage is the variable that we created earlier. {‘key’: #(token)} is the input that we provide.

#(token) allows you to get the value of the token variable.

So final version of our test is below.

Scenario: Login to Loadium
	* def doStorage =
"""
function(args) {
	var DataStorage = Java.type('examples.DataStorage');
	var dS = new DataStorage();
	return dS.write(args);
}
"""
	Given url 'https://account.loadium.com/uaa/oauth/token?grant_type=password&password=PASS&username=USER&scope=openid'
	And header Accept = 'application/json'
	And header Authorization = 'Basic dGVzdGluaXVtU3VpdGVUcnVzdGVkQ2xpZW50OnRlc3Rpbml1bVN1aXRlU2VjcmV0S2V5'
	And request {}
	Then method POST
	Then status 200
	* def token = $.access_token
	* def result = call doStorage {'key': #(token)}

Defining File Read Functionality into Karate Test

This test scenario fetches some data from the server. We need to provide a token to execute this scenario. Let’s do that.

Scenario: Get All Tests
	Given url 'https://loadium.io/resource1/api/tests'
	And header Accept = 'application/json'
	And header Authorization = 'Bearer ' + result
	Then method GET
	Then status 200
	* def testKey = $.testBasicDetailsDTOs[0].testKey

Once again we create a doStorage object calling our Java class’ read method.

* def doStorage =
"""
function(args) {
	var DataStorage = Java.type('examples.DataStorage');
	var dS = new DataStorage();
	return dS.read(args);
}""

This line creates an object with doStorage name that you will use in your Karate DSL test. Blue ones are the name of my Java file. The green one is the package name of my Java class. As you can see we create a variable dS then call read method. This is the method name that we have in Java class.

Calling File Read Functionality

Then we call our this object with an input. As we stored our token with “key” value, we pass “key” parameter to our method.

* def result = call doStorage 'key'

call is a built-in component of Karate framework. doStorage is the variable that we created earlier. The key is the input that we provide to that function. Then our test scenarios change as below:

Scenario: Get All Tests
	* def doStorage =
"""
function(args) {
	var DataStorage = Java.type('examples.DataStorage');
	var dS = new DataStorage();
	return dS.read(args);
}"""
	Given url 'https://loadium.io/resource1/api/tests'
	And header Accept = 'application/json'
	* def result = call doStorage 'key'
	And header Authorization = 'Bearer ' + result
	Then method GET
	Then status 200
	* def testKey = $.testBasicDetailsDTOs[0].testKey

As you can see, there are no limits to what you can achieve with Karate. You can find the project here: https://github.com/swtestacademy/Karate-API-Test-with-Java-Code

Thanks.
Canberk Akduygu

9 thoughts on “Calling Custom Java Code in Karate API Tests”

  1. Very cool! We were also facing this exact problem and considered using file reading/writing, but arrived at a slightly different solution. We used Karate’s built-in ‘callSingle’ function, since it allows you to save returned values across all features. In the config file, we use callSingle to call an initialization Karate feature file that calls the required login endpoint, and then returns the token value to the config file where we save it. That token value can then be used across every subsequent feature file we run, without having to use file reading/writing.

    Using Java code in Karate is a great feature too, we are using it for things like custom assertions, and uuid & local date time generation.

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.